1 # Copyright (C) 2017 Nippon Telegraph and Telephone Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 Zebra protocol parser/serializer
19 Zebra Protocol is used to communicate with the zebra daemon.
26 from distutils.version import LooseVersion
31 from ryu import flags as cfg_flags # For loading 'zapi' option definition
32 from ryu.cfg import CONF
33 from ryu.lib import addrconv
34 from ryu.lib import ip
35 from ryu.lib import stringify
36 from ryu.lib import type_desc
37 from . import packet_base
39 from . import safi as packet_safi
42 LOG = logging.getLogger(__name__)
44 # Default Zebra protocol version
46 _DEFAULT_FRR_VERSION = 4
48 _FRR_VERSION_2_0 = LooseVersion('2.0')
49 _FRR_VERSION_3_0 = LooseVersion('3.0')
51 # Constants in quagga/lib/zebra.h
53 # Default Zebra TCP port
57 ZEBRA_INTERFACE_ADD = 1
58 ZEBRA_INTERFACE_DELETE = 2
59 ZEBRA_INTERFACE_ADDRESS_ADD = 3
60 ZEBRA_INTERFACE_ADDRESS_DELETE = 4
61 ZEBRA_INTERFACE_UP = 5
62 ZEBRA_INTERFACE_DOWN = 6
63 ZEBRA_IPV4_ROUTE_ADD = 7
64 ZEBRA_IPV4_ROUTE_DELETE = 8
65 ZEBRA_IPV6_ROUTE_ADD = 9
66 ZEBRA_IPV6_ROUTE_DELETE = 10
67 ZEBRA_REDISTRIBUTE_ADD = 11
68 ZEBRA_REDISTRIBUTE_DELETE = 12
69 ZEBRA_REDISTRIBUTE_DEFAULT_ADD = 13
70 ZEBRA_REDISTRIBUTE_DEFAULT_DELETE = 14
71 ZEBRA_IPV4_NEXTHOP_LOOKUP = 15
72 ZEBRA_IPV6_NEXTHOP_LOOKUP = 16
73 ZEBRA_IPV4_IMPORT_LOOKUP = 17
74 ZEBRA_IPV6_IMPORT_LOOKUP = 18
75 ZEBRA_INTERFACE_RENAME = 19
76 ZEBRA_ROUTER_ID_ADD = 20
77 ZEBRA_ROUTER_ID_DELETE = 21
78 ZEBRA_ROUTER_ID_UPDATE = 22
80 ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB = 24
81 ZEBRA_VRF_UNREGISTER = 25
82 ZEBRA_INTERFACE_LINK_PARAMS = 26
83 ZEBRA_NEXTHOP_REGISTER = 27
84 ZEBRA_NEXTHOP_UNREGISTER = 28
85 ZEBRA_NEXTHOP_UPDATE = 29
86 ZEBRA_MESSAGE_MAX = 30
88 # Zebra message types on FRRouting
89 FRR_ZEBRA_INTERFACE_ADD = 0
90 FRR_ZEBRA_INTERFACE_DELETE = 1
91 FRR_ZEBRA_INTERFACE_ADDRESS_ADD = 2
92 FRR_ZEBRA_INTERFACE_ADDRESS_DELETE = 3
93 FRR_ZEBRA_INTERFACE_UP = 4
94 FRR_ZEBRA_INTERFACE_DOWN = 5
95 FRR_ZEBRA_IPV4_ROUTE_ADD = 6
96 FRR_ZEBRA_IPV4_ROUTE_DELETE = 7
97 FRR_ZEBRA_IPV6_ROUTE_ADD = 8
98 FRR_ZEBRA_IPV6_ROUTE_DELETE = 9
99 FRR_ZEBRA_REDISTRIBUTE_ADD = 10
100 FRR_ZEBRA_REDISTRIBUTE_DELETE = 11
101 FRR_ZEBRA_REDISTRIBUTE_DEFAULT_ADD = 12
102 FRR_ZEBRA_REDISTRIBUTE_DEFAULT_DELETE = 13
103 FRR_ZEBRA_ROUTER_ID_ADD = 14
104 FRR_ZEBRA_ROUTER_ID_DELETE = 15
105 FRR_ZEBRA_ROUTER_ID_UPDATE = 16
107 FRR_ZEBRA_NEXTHOP_REGISTER = 18
108 FRR_ZEBRA_NEXTHOP_UNREGISTER = 19
109 FRR_ZEBRA_NEXTHOP_UPDATE = 20
110 FRR_ZEBRA_INTERFACE_NBR_ADDRESS_ADD = 21
111 FRR_ZEBRA_INTERFACE_NBR_ADDRESS_DELETE = 22
112 FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE = 23
113 FRR_ZEBRA_IMPORT_ROUTE_REGISTER = 24
114 FRR_ZEBRA_IMPORT_ROUTE_UNREGISTER = 25
115 FRR_ZEBRA_IMPORT_CHECK_UPDATE = 26
116 FRR_ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD = 27
117 FRR_ZEBRA_BFD_DEST_REGISTER = 28
118 FRR_ZEBRA_BFD_DEST_DEREGISTER = 29
119 FRR_ZEBRA_BFD_DEST_UPDATE = 30
120 FRR_ZEBRA_BFD_DEST_REPLAY = 31
121 FRR_ZEBRA_REDISTRIBUTE_IPV4_ADD = 32
122 FRR_ZEBRA_REDISTRIBUTE_IPV4_DEL = 33
123 FRR_ZEBRA_REDISTRIBUTE_IPV6_ADD = 34
124 FRR_ZEBRA_REDISTRIBUTE_IPV6_DEL = 35
125 FRR_ZEBRA_VRF_UNREGISTER = 36
126 FRR_ZEBRA_VRF_ADD = 37
127 FRR_ZEBRA_VRF_DELETE = 38
128 FRR_ZEBRA_INTERFACE_VRF_UPDATE = 39
129 FRR_ZEBRA_BFD_CLIENT_REGISTER = 40
130 FRR_ZEBRA_INTERFACE_ENABLE_RADV = 41
131 FRR_ZEBRA_INTERFACE_DISABLE_RADV = 42
132 FRR_ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB = 43
133 FRR_ZEBRA_INTERFACE_LINK_PARAMS = 44
134 FRR_ZEBRA_MPLS_LABELS_ADD = 45
135 FRR_ZEBRA_MPLS_LABELS_DELETE = 46
136 FRR_ZEBRA_IPV4_NEXTHOP_ADD = 47
137 FRR_ZEBRA_IPV4_NEXTHOP_DELETE = 48
138 FRR_ZEBRA_IPV6_NEXTHOP_ADD = 49
139 FRR_ZEBRA_IPV6_NEXTHOP_DELETE = 50
142 ZEBRA_ROUTE_SYSTEM = 0
143 ZEBRA_ROUTE_KERNEL = 1
144 ZEBRA_ROUTE_CONNECT = 2
145 ZEBRA_ROUTE_STATIC = 3
147 ZEBRA_ROUTE_RIPNG = 5
149 ZEBRA_ROUTE_OSPF6 = 7
153 ZEBRA_ROUTE_HSLS = 11
154 ZEBRA_ROUTE_OLSR = 12
155 ZEBRA_ROUTE_BABEL = 13
158 # Zebra route types on FRRouting
159 FRR_ZEBRA_ROUTE_SYSTEM = 0
160 FRR_ZEBRA_ROUTE_KERNEL = 1
161 FRR_ZEBRA_ROUTE_CONNECT = 2
162 FRR_ZEBRA_ROUTE_STATIC = 3
163 FRR_ZEBRA_ROUTE_RIP = 4
164 FRR_ZEBRA_ROUTE_RIPNG = 5
165 FRR_ZEBRA_ROUTE_OSPF = 6
166 FRR_ZEBRA_ROUTE_OSPF6 = 7
167 FRR_ZEBRA_ROUTE_ISIS = 8
168 FRR_ZEBRA_ROUTE_BGP = 9
169 FRR_ZEBRA_ROUTE_PIM = 10
170 FRR_ZEBRA_ROUTE_HSLS = 11
171 FRR_ZEBRA_ROUTE_OLSR = 12
172 FRR_ZEBRA_ROUTE_TABLE = 13
173 FRR_ZEBRA_ROUTE_LDP = 14
174 FRR_ZEBRA_ROUTE_VNC = 15
175 FRR_ZEBRA_ROUTE_VNC_DIRECT = 16
176 FRR_ZEBRA_ROUTE_VNC_DIRECT_RH = 17
177 FRR_ZEBRA_ROUTE_BGP_DIRECT = 18
178 FRR_ZEBRA_ROUTE_BGP_DIRECT_EXT = 19
179 FRR_ZEBRA_ROUTE_ALL = 20
180 FRR_ZEBRA_ROUTE_MAX = 21
182 # Zebra message flags
183 ZEBRA_FLAG_INTERNAL = 0x01
184 ZEBRA_FLAG_SELFROUTE = 0x02
185 ZEBRA_FLAG_BLACKHOLE = 0x04
186 ZEBRA_FLAG_IBGP = 0x08
187 ZEBRA_FLAG_SELECTED = 0x10
188 ZEBRA_FLAG_FIB_OVERRIDE = 0x20
189 ZEBRA_FLAG_STATIC = 0x40
190 ZEBRA_FLAG_REJECT = 0x80
192 # Zebra message flags on FRRouting
193 FRR_ZEBRA_FLAG_INTERNAL = 0x01
194 FRR_ZEBRA_FLAG_SELFROUTE = 0x02
195 FRR_ZEBRA_FLAG_BLACKHOLE = 0x04
196 FRR_ZEBRA_FLAG_IBGP = 0x08
197 FRR_ZEBRA_FLAG_SELECTED = 0x10
198 FRR_ZEBRA_FLAG_STATIC = 0x40
199 FRR_ZEBRA_FLAG_REJECT = 0x80
200 FRR_ZEBRA_FLAG_SCOPE_LINK = 0x100
201 FRR_ZEBRA_FLAG_FIB_OVERRIDE = 0x200
203 # Zebra nexthop flags
204 ZEBRA_NEXTHOP_IFINDEX = 1
205 ZEBRA_NEXTHOP_IFNAME = 2
206 ZEBRA_NEXTHOP_IPV4 = 3
207 ZEBRA_NEXTHOP_IPV4_IFINDEX = 4
208 ZEBRA_NEXTHOP_IPV4_IFNAME = 5
209 ZEBRA_NEXTHOP_IPV6 = 6
210 ZEBRA_NEXTHOP_IPV6_IFINDEX = 7
211 ZEBRA_NEXTHOP_IPV6_IFNAME = 8
212 ZEBRA_NEXTHOP_BLACKHOLE = 9
214 # Zebra nexthop flags on FRRouting
215 FRR_ZEBRA_NEXTHOP_IFINDEX = 1
216 FRR_ZEBRA_NEXTHOP_IPV4 = 2
217 FRR_ZEBRA_NEXTHOP_IPV4_IFINDEX = 3
218 FRR_ZEBRA_NEXTHOP_IPV6 = 4
219 FRR_ZEBRA_NEXTHOP_IPV6_IFINDEX = 5
220 FRR_ZEBRA_NEXTHOP_BLACKHOLE = 6
222 # Constants in quagga/lib/zclient.h
224 # Zebra API message flags
225 ZAPI_MESSAGE_NEXTHOP = 0x01
226 ZAPI_MESSAGE_IFINDEX = 0x02
227 ZAPI_MESSAGE_DISTANCE = 0x04
228 ZAPI_MESSAGE_METRIC = 0x08
229 ZAPI_MESSAGE_MTU = 0x10
230 ZAPI_MESSAGE_TAG = 0x20
232 # Zebra API message flags on FRRouting.
233 # Note: Constants for TAG/MTU is inverted from Quagga version.
234 FRR_ZAPI_MESSAGE_NEXTHOP = 0x01
235 FRR_ZAPI_MESSAGE_IFINDEX = 0x02
236 FRR_ZAPI_MESSAGE_DISTANCE = 0x04
237 FRR_ZAPI_MESSAGE_METRIC = 0x08
238 FRR_ZAPI_MESSAGE_TAG = 0x10
239 FRR_ZAPI_MESSAGE_MTU = 0x20
240 FRR_ZAPI_MESSAGE_SRCPFX = 0x40
241 FRR_ZAPI_MESSAGE_LABEL = 0x80
243 # Constants in quagga/lib/if.h
245 # Interface name length
246 # Linux define value in /usr/include/linux/if.h.
247 # #define IFNAMSIZ 16
248 # FreeBSD define value in /usr/include/net/if.h.
249 # #define IFNAMSIZ 16
250 INTERFACE_NAMSIZE = 20
251 INTERFACE_HWADDR_MAX = 20
253 # Zebra internal interface status
254 ZEBRA_INTERFACE_ACTIVE = 1 << 0
255 ZEBRA_INTERFACE_SUB = 1 << 1
256 ZEBRA_INTERFACE_LINKDETECTION = 1 << 2
257 # Followings are extended on FRRouting
258 ZEBRA_INTERFACE_VRF_LOOPBACK = 1 << 3
260 # Zebra interface connected address flags
261 ZEBRA_IFA_SECONDARY = 1 << 0
262 ZEBRA_IFA_PEER = 1 << 1
263 ZEBRA_IFA_UNNUMBERED = 1 << 2
265 # Zebra link layer types
266 ZEBRA_LLT_UNKNOWN = 0
271 ZEBRA_LLT_IEEE802 = 5
273 ZEBRA_LLT_APPLETLK = 7
276 ZEBRA_LLT_METRICOM = 10
277 ZEBRA_LLT_IEEE1394 = 11
279 ZEBRA_LLT_INFINIBAND = 13
283 ZEBRA_LLT_CSLIP6 = 17
291 ZEBRA_LLT_RAWHDLC = 25
296 ZEBRA_LLT_LOOPBACK = 30
297 ZEBRA_LLT_LOCALTLK = 31
302 ZEBRA_LLT_IP6GRE = 36
303 ZEBRA_LLT_PIMREG = 37
305 ZEBRA_LLT_ECONET = 39
310 ZEBRA_LLT_FCFABRIC = 44
311 ZEBRA_LLT_IEEE802_TR = 45
312 ZEBRA_LLT_IEEE80211 = 46
313 ZEBRA_LLT_IEEE80211_RADIOTAP = 47
314 ZEBRA_LLT_IEEE802154 = 48
315 ZEBRA_LLT_IEEE802154_PHY = 49
317 # Link Parameters Status
321 LP_MAX_RSV_BW = 0x0004
327 LP_DELAY_VAR = 0x0100
332 LP_TE_METRIC = 0x2000
334 # "non-official" architectural constants
337 # Constants in frr/zebra/zebra_ptm.h
339 # Interface PTM Enable configuration
340 ZEBRA_IF_PTM_ENABLE_OFF = 0
341 ZEBRA_IF_PTM_ENABLE_ON = 1
342 ZEBRA_IF_PTM_ENABLE_UNSPEC = 2
345 ZEBRA_PTM_STATUS_DOWN = 0
346 ZEBRA_PTM_STATUS_UP = 1
347 ZEBRA_PTM_STATUS_UNKNOWN = 2
349 # Constants in frr/lib/bfd.h
352 BFD_STATUS_UNKNOWN = 1 << 0
353 BFD_STATUS_DOWN = 1 << 1
354 BFD_STATUS_UP = 1 << 2
356 # Constants in frr/lib/vrf.h
361 # Constants in frr/lib/mpls.h
363 # Reserved MPLS label values
364 MPLS_V4_EXP_NULL_LABEL = 0
366 MPLS_V6_EXP_NULL_LABEL = 2
367 MPLS_IMP_NULL_LABEL = 3
368 MPLS_ENTROPY_LABEL_INDICATOR = 7
370 MPLS_OAM_ALERT_LABEL = 14
371 MPLS_EXTENSION_LABEL = 15
372 MPLS_MIN_RESERVED_LABEL = 0
373 MPLS_MAX_RESERVED_LABEL = 15
374 MPLS_MIN_UNRESERVED_LABEL = 16
375 MPLS_MAX_UNRESERVED_LABEL = 1048575
378 # Utility functions/classes
380 IPv4Prefix = bgp.IPAddrPrefix
381 IPv6Prefix = bgp.IP6AddrPrefix
384 def _parse_ip_prefix(family, buf):
385 if family == socket.AF_INET:
386 prefix, rest = bgp.IPAddrPrefix.parser(buf)
387 elif family == socket.AF_INET6:
388 prefix, rest = IPv6Prefix.parser(buf)
390 raise struct.error('Unsupported family: %d' % family)
392 return prefix.prefix, rest
395 def _serialize_ip_prefix(prefix):
396 if ip.valid_ipv4(prefix):
397 prefix_addr, prefix_num = prefix.split('/')
398 return bgp.IPAddrPrefix(int(prefix_num), prefix_addr).serialize()
399 elif ip.valid_ipv6(prefix):
400 prefix_addr, prefix_num = prefix.split('/')
401 return IPv6Prefix(int(prefix_num), prefix_addr).serialize()
403 raise ValueError('Invalid prefix: %s' % prefix)
406 # Family and Zebra Prefix format:
408 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
409 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
411 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
412 # | IPv4/v6 prefix (4 bytes or 16 bytes) |
413 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
416 _ZEBRA_FAMILY_FMT = '!B' # family
417 _ZEBRA_FAMILY_SIZE = struct.calcsize(_ZEBRA_FAMILY_FMT)
418 _ZEBRA_IPV4_PREFIX_FMT = '!4sB' # prefix, prefix_len
419 _ZEBRA_IPV6_PREFIX_FMT = '!16sB'
420 _ZEBRA_IPV4_PREFIX_SIZE = struct.calcsize(_ZEBRA_IPV4_PREFIX_FMT)
421 _ZEBRA_IPV6_PREFIX_SIZE = struct.calcsize(_ZEBRA_IPV6_PREFIX_FMT)
422 _ZEBRA_FAMILY_IPV4_PREFIX_FMT = '!B4sB' # family, prefix, prefix_len
423 _ZEBRA_FAMILY_IPV6_PREFIX_FMT = '!B16sB' # family, prefix, prefix_len
426 def _parse_zebra_family_prefix(buf):
428 Parses family and prefix in Zebra format.
430 (family,) = struct.unpack_from(_ZEBRA_FAMILY_FMT, buf)
431 rest = buf[_ZEBRA_FAMILY_SIZE:]
433 if socket.AF_INET == family:
434 (prefix, p_len) = struct.unpack_from(_ZEBRA_IPV4_PREFIX_FMT, rest)
435 prefix = '%s/%d' % (addrconv.ipv4.bin_to_text(prefix), p_len)
436 rest = rest[_ZEBRA_IPV4_PREFIX_SIZE:]
437 elif socket.AF_INET6 == family:
438 (prefix, p_len) = struct.unpack_from(_ZEBRA_IPV6_PREFIX_FMT, rest)
439 prefix = '%s/%d' % (addrconv.ipv6.bin_to_text(prefix), p_len)
440 rest = rest[_ZEBRA_IPV6_PREFIX_SIZE:]
442 raise struct.error('Unsupported family: %d' % family)
444 return family, prefix, rest
447 def _serialize_zebra_family_prefix(prefix):
449 Serializes family and prefix in Zebra format.
451 if ip.valid_ipv4(prefix):
452 family = socket.AF_INET # fixup
453 prefix_addr, prefix_num = prefix.split('/')
454 return family, struct.pack(
455 _ZEBRA_FAMILY_IPV4_PREFIX_FMT,
457 addrconv.ipv4.text_to_bin(prefix_addr),
459 elif ip.valid_ipv6(prefix):
460 family = socket.AF_INET6 # fixup
461 prefix_addr, prefix_num = prefix.split('/')
462 return family, struct.pack(
463 _ZEBRA_FAMILY_IPV6_PREFIX_FMT,
465 addrconv.ipv6.text_to_bin(prefix_addr),
468 raise ValueError('Invalid prefix: %s' % prefix)
471 def _is_frr_version_ge(compared_version):
472 return CONF['zapi'].frr_version >= compared_version
475 class InterfaceLinkParams(stringify.StringifyMixin):
477 Interface Link Parameters class for if_link_params structure.
479 # Interface Link Parameters structure:
481 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
482 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
483 # | Status of Link Parameters |
484 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
485 # | Traffic Engineering metric |
486 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
487 # | (float) Maximum Bandwidth |
488 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
489 # | (float) Maximum Reservable Bandwidth |
490 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
491 # | Number of Unreserved Bandwidth Classes (max is MAX_CLASS_TYPE)|
492 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
493 # | (float) Unreserved Bandwidth per Class Type |
494 # | ... repeats Number of Unreserved Bandwidth Classes times |
495 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
496 # | Administrative group |
497 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
498 # | Remote AS number |
499 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
500 # | Remote IP address |
501 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
502 # | Link Average Delay |
503 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
505 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
507 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
508 # | Link Delay Variation |
509 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
510 # | (float) Link Packet Loss |
511 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
512 # | (float) Residual Bandwidth |
513 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
514 # | (float) Available Bandwidth |
515 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516 # | (float) Utilized Bandwidth |
517 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
518 # lp_status, te_metric, max_bw, max_reserved_bw, bw_cls_num
519 _HEADER_FMT = '!IIffI'
520 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
522 REPEATED_SIZE = struct.calcsize(_REPEATED_FMT)
523 # admin_group, remote_as, remote_ip,
524 # average_delay, min_delay, max_delay, delay_var,
525 # pkt_loss, residual_bw, average_bw, utilized_bw
526 _FOOTER_FMT = '!II4sIIIIffff'
527 FOOTER_SIZE = struct.calcsize(_FOOTER_FMT)
529 def __init__(self, lp_status, te_metric, max_bw, max_reserved_bw,
530 unreserved_bw, admin_group, remote_as, remote_ip,
531 average_delay, min_delay, max_delay, delay_var, pkt_loss,
532 residual_bw, average_bw, utilized_bw):
533 super(InterfaceLinkParams, self).__init__()
534 self.lp_status = lp_status
535 self.te_metric = te_metric
537 self.max_reserved_bw = max_reserved_bw
538 assert isinstance(unreserved_bw, (list, tuple))
539 assert len(unreserved_bw) == MAX_CLASS_TYPE
540 self.unreserved_bw = unreserved_bw
541 self.admin_group = admin_group
542 self.remote_as = remote_as
543 assert ip.valid_ipv4(remote_ip)
544 self.remote_ip = remote_ip
545 self.average_delay = average_delay
546 self.min_delay = min_delay
547 self.max_delay = max_delay
548 self.delay_var = delay_var
549 self.pkt_loss = pkt_loss
550 self.residual_bw = residual_bw
551 self.average_bw = average_bw
552 self.utilized_bw = utilized_bw
556 (lp_status, te_metric, max_bw, max_reserved_bw,
557 bw_cls_num) = struct.unpack_from(cls._HEADER_FMT, buf)
558 if MAX_CLASS_TYPE < bw_cls_num:
559 bw_cls_num = MAX_CLASS_TYPE
560 offset = cls.HEADER_SIZE
563 for _ in range(bw_cls_num):
564 (u_bw,) = struct.unpack_from(cls._REPEATED_FMT, buf, offset)
565 unreserved_bw.append(u_bw)
566 offset += cls.REPEATED_SIZE
568 (admin_group, remote_as, remote_ip, average_delay, min_delay,
569 max_delay, delay_var, pkt_loss, residual_bw, average_bw,
570 utilized_bw) = struct.unpack_from(
571 cls._FOOTER_FMT, buf, offset)
572 offset += cls.FOOTER_SIZE
574 remote_ip = addrconv.ipv4.bin_to_text(remote_ip)
576 return cls(lp_status, te_metric, max_bw, max_reserved_bw,
577 unreserved_bw, admin_group, remote_as, remote_ip,
578 average_delay, min_delay, max_delay, delay_var, pkt_loss,
579 residual_bw, average_bw, utilized_bw), buf[offset:]
583 self._HEADER_FMT, self.lp_status, self.te_metric, self.max_bw,
584 self.max_reserved_bw, len(self.unreserved_bw))
586 for u_bw in self.unreserved_bw:
587 buf += struct.pack(self._REPEATED_FMT, u_bw)
589 remote_ip = addrconv.ipv4.text_to_bin(self.remote_ip)
592 self._FOOTER_FMT, self.admin_group, self.remote_as, remote_ip,
593 self.average_delay, self.min_delay, self.max_delay,
594 self.delay_var, self.pkt_loss, self.residual_bw, self.average_bw,
600 @six.add_metaclass(abc.ABCMeta)
601 class _NextHop(type_desc.TypeDisp, stringify.StringifyMixin):
603 Base class for Zebra Nexthop structure.
605 # Zebra Nexthop structure:
607 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
608 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
610 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
611 # | IPv4/v6 address or Interface Index number (Variable) |
612 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
614 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
616 def __init__(self, ifindex=None, ifname=None, addr=None, type_=None):
617 super(_NextHop, self).__init__()
618 self.ifindex = ifindex
626 (type_,) = struct.unpack_from(cls._HEADER_FMT, buf)
627 rest = buf[cls.HEADER_SIZE:]
629 subcls = cls._lookup_type(type_)
631 raise struct.error('unsupported Nexthop type: %d' % type_)
633 nexthop, rest = subcls.parse(rest)
638 def _serialize(self):
641 def serialize(self, version=_DEFAULT_VERSION):
642 if self.type is None:
649 'Unsupported Zebra protocol version: %d' % version)
650 self.type = nh_cls._rev_lookup_type(self.__class__)
651 return struct.pack(self._HEADER_FMT, self.type) + self._serialize()
654 @six.add_metaclass(abc.ABCMeta)
655 class _FrrNextHop(_NextHop):
657 Base class for Zebra Nexthop structure for translating nexthop types
662 _NEXTHOP_COUNT_FMT = '!B' # nexthop_count
663 _NEXTHOP_COUNT_SIZE = struct.calcsize(_NEXTHOP_COUNT_FMT)
666 def _parse_nexthops(buf, version=_DEFAULT_VERSION):
667 (nexthop_count,) = struct.unpack_from(_NEXTHOP_COUNT_FMT, buf)
668 rest = buf[_NEXTHOP_COUNT_SIZE:]
676 'Unsupported Zebra protocol version: %d' % version)
679 for _ in range(nexthop_count):
680 nexthop, rest = nh_cls.parse(rest)
681 nexthops.append(nexthop)
683 return nexthops, rest
686 def _serialize_nexthops(nexthops, version=_DEFAULT_VERSION):
687 nexthop_count = len(nexthops)
688 buf = struct.pack(_NEXTHOP_COUNT_FMT, nexthop_count)
690 if nexthop_count == 0:
693 for nexthop in nexthops:
694 buf += nexthop.serialize(version=version)
699 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IFINDEX)
700 @_NextHop.register_type(ZEBRA_NEXTHOP_IFINDEX)
701 class NextHopIFIndex(_NextHop):
703 Nexthop class for ZEBRA_NEXTHOP_IFINDEX type.
705 _BODY_FMT = '!I' # ifindex
706 BODY_SIZE = struct.calcsize(_BODY_FMT)
710 (ifindex,) = struct.unpack_from(cls._BODY_FMT, buf)
711 rest = buf[cls.BODY_SIZE:]
713 return cls(ifindex=ifindex), rest
715 def _serialize(self):
716 return struct.pack(self._BODY_FMT, self.ifindex)
719 @_NextHop.register_type(ZEBRA_NEXTHOP_IFNAME)
720 class NextHopIFName(_NextHop):
722 Nexthop class for ZEBRA_NEXTHOP_IFNAME type.
724 _BODY_FMT = '!I' # ifindex
725 BODY_SIZE = struct.calcsize(_BODY_FMT)
729 (ifindex,) = struct.unpack_from(cls._BODY_FMT, buf)
730 rest = buf[cls.BODY_SIZE:]
732 return cls(ifindex=ifindex), rest
734 def _serialize(self):
735 return struct.pack(self._BODY_FMT, self.ifindex)
738 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV4)
739 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV4)
740 class NextHopIPv4(_NextHop):
742 Nexthop class for ZEBRA_NEXTHOP_IPV4 type.
744 _BODY_FMT = '!4s' # addr(IPv4)
745 BODY_SIZE = struct.calcsize(_BODY_FMT)
746 _BODY_FMT_FRR_V3 = '!4sI' # addr(IPv4), ifindex
747 BODY_SIZE_FRR_V3 = struct.calcsize(_BODY_FMT_FRR_V3)
751 if _is_frr_version_ge(_FRR_VERSION_3_0):
752 (addr, ifindex) = struct.unpack_from(cls._BODY_FMT_FRR_V3, buf)
753 addr = addrconv.ipv4.bin_to_text(addr)
754 rest = buf[cls.BODY_SIZE_FRR_V3:]
755 return cls(ifindex=ifindex, addr=addr), rest
757 addr = addrconv.ipv4.bin_to_text(buf[:cls.BODY_SIZE])
758 rest = buf[cls.BODY_SIZE:]
760 return cls(addr=addr), rest
762 def _serialize(self):
763 if _is_frr_version_ge(_FRR_VERSION_3_0) and self.ifindex:
764 addr = addrconv.ipv4.text_to_bin(self.addr)
765 return struct.pack(self._BODY_FMT_FRR_V3, addr, self.ifindex)
767 return addrconv.ipv4.text_to_bin(self.addr)
770 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV4_IFINDEX)
771 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV4_IFINDEX)
772 class NextHopIPv4IFIndex(_NextHop):
774 Nexthop class for ZEBRA_NEXTHOP_IPV4_IFINDEX type.
776 _BODY_FMT = '!4sI' # addr(IPv4), ifindex
777 BODY_SIZE = struct.calcsize(_BODY_FMT)
781 (addr, ifindex) = struct.unpack_from(cls._BODY_FMT, buf)
782 addr = addrconv.ipv4.bin_to_text(addr)
783 rest = buf[cls.BODY_SIZE:]
785 return cls(ifindex=ifindex, addr=addr), rest
787 def _serialize(self):
788 addr = addrconv.ipv4.text_to_bin(self.addr)
790 return struct.pack(self._BODY_FMT, addr, self.ifindex)
793 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV4_IFNAME)
794 class NextHopIPv4IFName(_NextHop):
796 Nexthop class for ZEBRA_NEXTHOP_IPV4_IFNAME type.
798 _BODY_FMT = '!4sI' # addr(IPv4), ifindex
799 BODY_SIZE = struct.calcsize(_BODY_FMT)
803 (addr, ifindex) = struct.unpack_from(cls._BODY_FMT, buf)
804 addr = addrconv.ipv4.bin_to_text(addr)
805 rest = buf[cls.BODY_SIZE:]
807 return cls(ifindex=ifindex, addr=addr), rest
809 def _serialize(self):
810 addr = addrconv.ipv4.text_to_bin(self.addr)
812 return struct.pack(self._BODY_FMT, addr, self.ifindex)
815 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV6)
816 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV6)
817 class NextHopIPv6(_NextHop):
819 Nexthop class for ZEBRA_NEXTHOP_IPV6 type.
821 _BODY_FMT = '!16s' # addr(IPv6)
822 BODY_SIZE = struct.calcsize(_BODY_FMT)
823 _BODY_FMT_FRR_V3 = '!16sI' # addr(IPv6), ifindex
824 BODY_SIZE_FRR_V3 = struct.calcsize(_BODY_FMT_FRR_V3)
828 if _is_frr_version_ge(_FRR_VERSION_3_0):
829 (addr, ifindex) = struct.unpack_from(cls._BODY_FMT_FRR_V3, buf)
830 addr = addrconv.ipv4.bin_to_text(addr)
831 rest = buf[cls.BODY_SIZE_FRR_V3:]
832 return cls(ifindex=ifindex, addr=addr), rest
834 addr = addrconv.ipv6.bin_to_text(buf[:cls.BODY_SIZE])
835 rest = buf[cls.BODY_SIZE:]
837 return cls(addr=addr), rest
839 def _serialize(self):
840 if _is_frr_version_ge(_FRR_VERSION_3_0) and self.ifindex:
841 addr = addrconv.ipv4.text_to_bin(self.addr)
842 return struct.pack(self._BODY_FMT_FRR_V3, addr, self.ifindex)
844 return addrconv.ipv6.text_to_bin(self.addr)
847 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV6_IFINDEX)
848 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV6_IFINDEX)
849 class NextHopIPv6IFIndex(_NextHop):
851 Nexthop class for ZEBRA_NEXTHOP_IPV6_IFINDEX type.
853 _BODY_FMT = '!16sI' # addr(IPv6), ifindex
854 BODY_SIZE = struct.calcsize(_BODY_FMT)
858 (addr, ifindex) = struct.unpack_from(cls._BODY_FMT, buf)
859 addr = addrconv.ipv6.bin_to_text(addr)
860 rest = buf[cls.BODY_SIZE:]
862 return cls(ifindex=ifindex, addr=addr), rest
864 def _serialize(self):
865 addr = addrconv.ipv6.text_to_bin(self.addr)
867 return struct.pack(self._BODY_FMT, addr, self.ifindex)
870 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV6_IFNAME)
871 class NextHopIPv6IFName(_NextHop):
873 Nexthop class for ZEBRA_NEXTHOP_IPV6_IFNAME type.
875 _BODY_FMT = '!16sI' # addr(IPv6), ifindex
876 BODY_SIZE = struct.calcsize(_BODY_FMT)
880 (addr, ifindex) = struct.unpack_from(cls._BODY_FMT, buf)
881 addr = addrconv.ipv6.bin_to_text(addr)
882 rest = buf[cls.BODY_SIZE:]
884 return cls(ifindex=ifindex, addr=addr), rest
886 def _serialize(self):
887 addr = addrconv.ipv6.text_to_bin(self.addr)
889 return struct.pack(self._BODY_FMT, addr, self.ifindex)
892 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_BLACKHOLE)
893 @_NextHop.register_type(ZEBRA_NEXTHOP_BLACKHOLE)
894 class NextHopBlackhole(_NextHop):
896 Nexthop class for ZEBRA_NEXTHOP_BLACKHOLE type.
903 def _serialize(self):
907 class RegisteredNexthop(stringify.StringifyMixin):
909 Unit of ZEBRA_NEXTHOP_REGISTER message body.
911 # Unit of Zebra Nexthop Register message body:
913 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
914 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
915 # | Connected | Family |
916 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
917 # | IPv4/v6 Prefix (Variable) |
918 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
920 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
921 # Note: connected is renamed to flags on FRRouting.
923 def __init__(self, connected, family, prefix):
924 super(RegisteredNexthop, self).__init__()
925 self.connected = connected
927 if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
928 prefix = prefix.prefix
933 return self.connected
941 (connected, family) = struct.unpack_from(cls._HEADER_FMT, buf)
942 rest = buf[cls.HEADER_SIZE:]
944 prefix, rest = _parse_ip_prefix(family, rest)
946 return cls(connected, family, prefix), rest
949 buf = struct.pack(self._HEADER_FMT, self.connected, self.family)
951 return buf + _serialize_ip_prefix(self.prefix)
954 # Zebra message class
956 class ZebraMessage(packet_base.PacketBase):
958 Zebra protocol parser/serializer class.
960 An instance has the following attributes at least.
961 Most of them are same to the on-wire counterparts but in host byte order.
962 __init__ takes the corresponding args in this order.
964 ============== ==========================================================
965 Attribute Description
966 ============== ==========================================================
967 length Total packet length including this header.
968 The minimum length is 3 bytes for version 0 messages,
969 6 bytes for version 1/2 messages and 8 bytes for version
971 version Version number of the Zebra protocol message.
972 To instantiate messages with other than the default
973 version, ``version`` must be specified.
974 vrf_id VRF ID for the route contained in message.
975 Not present in version 0/1/2 messages in the on-wire
976 structure, and always 0 for theses version.
977 command Zebra Protocol command, which denotes message type.
979 An instance of subclass of ``_ZebraMessageBody`` named
980 like "Zebra + <message name>" (e.g., ``ZebraHello``).
981 Or ``None`` if message does not contain any body.
982 ============== ==========================================================
986 To instantiate Zebra messages, ``command`` can be omitted when the
987 valid ``body`` is specified.
991 >>> from ryu.lib.packet import zebra
992 >>> zebra.ZebraMessage(body=zebra.ZebraHello())
993 ZebraMessage(body=ZebraHello(route_type=14),command=23,
994 length=None,version=3,vrf_id=0)
996 On the other hand, if ``body`` is omitted, ``command`` must be
1001 >>> zebra.ZebraMessage(command=zebra.ZEBRA_INTERFACE_ADD)
1002 ZebraMessage(body=None,command=1,length=None,version=3,vrf_id=0)
1005 # Zebra Protocol Common Header (version 0):
1007 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1008 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1009 # | Length | Command |
1010 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1011 _V0_HEADER_FMT = '!HB'
1012 V0_HEADER_SIZE = struct.calcsize(_V0_HEADER_FMT)
1013 _MIN_LEN = V0_HEADER_SIZE
1015 # Zebra Protocol Common Header (version 1):
1017 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1018 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1019 # | Length | Marker | Version |
1020 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1022 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1023 _V1_HEADER_FMT = '!HBBH'
1024 V1_HEADER_SIZE = struct.calcsize(_V1_HEADER_FMT)
1026 # Zebra Protocol Common Header (version 3):
1028 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1029 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1030 # | Length | Marker | Version |
1031 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1032 # | VRF ID | Command |
1033 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1034 _V3_HEADER_FMT = '!HBBHH'
1035 V3_HEADER_SIZE = struct.calcsize(_V3_HEADER_FMT)
1037 # Note: Marker should be 0xff(=255) in the version>=1 header.
1038 # Also, FRRouting uses the different marker value.
1042 def __init__(self, length=None, version=_DEFAULT_VERSION,
1043 vrf_id=0, command=None, body=None):
1044 super(ZebraMessage, self).__init__()
1045 self.length = length
1046 self.version = version
1047 self.vrf_id = vrf_id
1048 self.command = command
1051 def _fill_command(self):
1052 assert isinstance(self.body, _ZebraMessageBody)
1053 body_base_cls = _ZebraMessageBody
1054 if self.version == 4:
1055 body_base_cls = _FrrZebraMessageBody
1056 self.command = body_base_cls.rev_lookup_command(self.body.__class__)
1059 def get_header_size(cls, version):
1061 return cls.V0_HEADER_SIZE
1062 elif version in [1, 2]:
1063 return cls.V1_HEADER_SIZE
1064 elif version in [3, 4]:
1065 return cls.V3_HEADER_SIZE
1068 'Unsupported Zebra protocol version: %d'
1072 def parse_header(cls, buf):
1073 (length, marker) = struct.unpack_from(cls._V0_HEADER_FMT, buf)
1074 if marker not in [cls._MARKER, cls._LT_MARKER]:
1076 body_buf = buf[cls.V0_HEADER_SIZE:length]
1077 # version=0, vrf_id=0
1078 return length, 0, 0, command, body_buf
1080 (length, marker, version, command) = struct.unpack_from(
1081 cls._V1_HEADER_FMT, buf)
1082 if version in [1, 2]:
1083 body_buf = buf[cls.V1_HEADER_SIZE:length]
1085 return length, version, 0, command, body_buf
1087 (length, marker, version, vrf_id, command) = struct.unpack_from(
1088 cls._V3_HEADER_FMT, buf)
1089 if version == 3 or (version == 4 and marker == cls._LT_MARKER):
1090 body_buf = buf[cls.V3_HEADER_SIZE:length]
1091 return length, version, vrf_id, command, body_buf
1094 'Failed to parse Zebra protocol header: '
1095 'marker=%d, version=%d' % (marker, version))
1098 def get_body_class(cls, version, command):
1100 return _FrrZebraMessageBody.lookup_command(command)
1102 return _ZebraMessageBody.lookup_command(command)
1105 def _parser_impl(cls, buf, from_zebra=False):
1106 buf = six.binary_type(buf)
1107 (length, version, vrf_id, command,
1108 body_buf) = cls.parse_header(buf)
1111 body_cls = cls.get_body_class(version, command)
1113 body = body_cls.parse_from_zebra(body_buf, version=version)
1115 body = body_cls.parse(body_buf, version=version)
1122 return (cls(length, version, vrf_id, command, body),
1123 _ZebraMessageFromZebra, rest)
1125 return cls(length, version, vrf_id, command, body), cls, rest
1128 def parser(cls, buf):
1129 return cls._parser_impl(buf)
1131 def serialize_header(self, body_len):
1132 if self.version == 0:
1133 self.length = self.V0_HEADER_SIZE + body_len # fixup
1135 self._V0_HEADER_FMT,
1136 self.length, self.command)
1137 elif self.version in [1, 2]:
1138 self.length = self.V1_HEADER_SIZE + body_len # fixup
1140 self._V1_HEADER_FMT,
1141 self.length, self._MARKER, self.version,
1143 elif self.version in [3, 4]:
1144 if self.version == 3:
1145 _marker = self._MARKER
1146 else: # self.version == 4
1147 _marker = self._LT_MARKER
1148 self.length = self.V3_HEADER_SIZE + body_len # fixup
1150 self._V3_HEADER_FMT,
1151 self.length, _marker, self.version,
1152 self.vrf_id, self.command)
1155 'Unsupported Zebra protocol version: %d'
1158 def serialize(self, _payload=None, _prev=None):
1159 if self.body is None:
1160 assert self.command is not None
1163 assert isinstance(self.body, _ZebraMessageBody)
1164 self._fill_command() # fixup
1165 body = self.body.serialize(version=self.version)
1167 return self.serialize_header(len(body)) + body
1170 class _ZebraMessageFromZebra(ZebraMessage):
1172 This class is corresponding to the message sent from Zebra daemon.
1176 def parser(cls, buf):
1177 return ZebraMessage._parser_impl(buf, from_zebra=True)
1181 zebra = ZebraMessage
1184 # Zebra message body classes
1186 class _ZebraMessageBody(type_desc.TypeDisp, stringify.StringifyMixin):
1188 Base class for Zebra message body.
1192 def lookup_command(cls, command):
1193 return cls._lookup_type(command)
1196 def rev_lookup_command(cls, body_cls):
1197 return cls._rev_lookup_type(body_cls)
1200 def parse(cls, buf, version=_DEFAULT_VERSION):
1204 def parse_from_zebra(cls, buf, version=_DEFAULT_VERSION):
1205 return cls.parse(buf, version=version)
1207 def serialize(self, version=_DEFAULT_VERSION):
1211 class _FrrZebraMessageBody(_ZebraMessageBody):
1213 Pseudo message body class for translating message types on FRRouting.
1217 @_FrrZebraMessageBody.register_unknown_type()
1218 @_ZebraMessageBody.register_unknown_type()
1219 class ZebraUnknownMessage(_ZebraMessageBody):
1221 Message body class for Unknown command.
1224 def __init__(self, buf):
1225 super(ZebraUnknownMessage, self).__init__()
1229 def parse(cls, buf, version=_DEFAULT_VERSION):
1232 def serialize(self, version=_DEFAULT_VERSION):
1236 @six.add_metaclass(abc.ABCMeta)
1237 class _ZebraInterface(_ZebraMessageBody):
1239 Base class for ZEBRA_INTERFACE_ADD, ZEBRA_INTERFACE_DELETE,
1240 ZEBRA_INTERFACE_UP and ZEBRA_INTERFACE_DOWN message body.
1242 # Zebra Interface Add/Delete message body:
1244 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1245 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1246 # | Interface Name (INTERFACE_NAMSIZE bytes length) |
1251 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1252 # | Interface index |
1253 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1255 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1256 # | Interface flags |
1258 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1259 # | (PTM Enable) | (PTM Status) | v4(FRRouting)
1260 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1262 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1263 # | (Speed): v4(FRRouting v3.0 or later) |
1264 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1265 # | Interface's MTU for IPv4 |
1266 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1267 # | Interface's MTU for IPv6 |
1268 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1270 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1271 # | (Link Layer Type): v3 or later |
1272 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1273 # | Hardware Address Length |
1274 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1275 # | Hardware Address if HW length different from 0 |
1276 # | ... max is INTERFACE_HWADDR_MAX |
1277 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1278 # | link_params? | Whether a link-params follows: 1 or 0.
1279 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1280 # | Link params 0 or 1 INTERFACE_LINK_PARAMS_SIZE sized |
1281 # | .... (struct if_link_params). |
1282 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1283 # ifname, ifindex, status, if_flags, metric, ifmtu, ifmtu6, bandwidth,
1285 _HEADER_FMT = '!%dsIBQIIIII' % INTERFACE_NAMSIZE
1286 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
1287 # ifname, ifindex, status, if_flags, metric, ifmtu, ifmtu6, bandwidth,
1288 # ll_type, hw_addr_len
1289 _V3_HEADER_FMT = '!%dsIBQIIIIII' % INTERFACE_NAMSIZE
1290 V3_HEADER_SIZE = struct.calcsize(_V3_HEADER_FMT)
1291 # ifname, ifindex, status, if_flags, ptm_enable, ptm_status, metric,
1292 # ifmtu, ifmtu6, bandwidth, ll_type, hw_addr_len
1293 _V4_HEADER_FMT_2_0 = '!%dsIBQBBIIIIII' % INTERFACE_NAMSIZE
1294 V4_HEADER_SIZE_2_0 = struct.calcsize(_V4_HEADER_FMT_2_0)
1295 # ifname, ifindex, status, if_flags, ptm_enable, ptm_status, metric,
1296 # speed, ifmtu, ifmtu6, bandwidth, ll_type, hw_addr_len
1297 _V4_HEADER_FMT_3_0 = '!%dsIBQBBIIIIIII' % INTERFACE_NAMSIZE
1298 V4_HEADER_SIZE_3_0 = struct.calcsize(_V4_HEADER_FMT_3_0)
1300 # link_params_state (whether a link-params follows)
1301 _LP_STATE_FMT = '!?'
1302 LP_STATE_SIZE = struct.calcsize(_LP_STATE_FMT)
1303 # See InterfaceLinkParams class for Link params structure
1305 def __init__(self, ifname=None, ifindex=None, status=None, if_flags=None,
1306 ptm_enable=None, ptm_status=None,
1307 metric=None, speed=None, ifmtu=None, ifmtu6=None,
1308 bandwidth=None, ll_type=None, hw_addr_len=0, hw_addr=None,
1310 super(_ZebraInterface, self).__init__()
1311 self.ifname = ifname
1312 self.ifindex = ifindex
1313 self.status = status
1314 self.if_flags = if_flags
1315 self.ptm_enable = ptm_enable
1316 self.ptm_status = ptm_status
1317 self.metric = metric
1320 self.ifmtu6 = ifmtu6
1321 self.bandwidth = bandwidth
1322 self.ll_type = ll_type
1323 self.hw_addr_lenght = hw_addr_len
1324 hw_addr = hw_addr or b''
1325 self.hw_addr = hw_addr
1326 assert (isinstance(link_params, InterfaceLinkParams)
1327 or link_params is None)
1328 self.link_params = link_params
1331 def parse(cls, buf, version=_DEFAULT_VERSION):
1337 (ifname, ifindex, status, if_flags, metric,
1338 ifmtu, ifmtu6, bandwidth,
1339 hw_addr_len) = struct.unpack_from(cls._HEADER_FMT, buf)
1340 rest = buf[cls.HEADER_SIZE:]
1342 (ifname, ifindex, status, if_flags, metric,
1343 ifmtu, ifmtu6, bandwidth, ll_type,
1344 hw_addr_len) = struct.unpack_from(cls._V3_HEADER_FMT, buf)
1345 rest = buf[cls.V3_HEADER_SIZE:]
1347 if _is_frr_version_ge(_FRR_VERSION_3_0):
1348 (ifname, ifindex, status, if_flags, ptm_enable, ptm_status,
1349 metric, speed, ifmtu, ifmtu6, bandwidth, ll_type,
1350 hw_addr_len) = struct.unpack_from(cls._V4_HEADER_FMT_3_0, buf)
1351 rest = buf[cls.V4_HEADER_SIZE_3_0:]
1352 elif _is_frr_version_ge(_FRR_VERSION_2_0):
1353 (ifname, ifindex, status, if_flags, ptm_enable, ptm_status,
1354 metric, ifmtu, ifmtu6, bandwidth, ll_type,
1355 hw_addr_len) = struct.unpack_from(cls._V4_HEADER_FMT_2_0, buf)
1356 rest = buf[cls.V4_HEADER_SIZE_2_0:]
1359 'Unsupported FRRouting version: %s'
1360 % CONF['zapi'].frr_version)
1363 'Unsupported Zebra protocol version: %d'
1365 ifname = str(six.text_type(ifname.strip(b'\x00'), 'ascii'))
1367 hw_addr_len = min(hw_addr_len, INTERFACE_HWADDR_MAX)
1368 hw_addr_bin = rest[:hw_addr_len]
1369 rest = rest[hw_addr_len:]
1370 if 0 < hw_addr_len < 7:
1371 # Assuming MAC address
1372 hw_addr = addrconv.mac.bin_to_text(
1373 hw_addr_bin + b'\x00' * (6 - hw_addr_len))
1375 # Unknown hardware address
1376 hw_addr = hw_addr_bin
1379 return cls(ifname, ifindex, status, if_flags,
1380 ptm_enable, ptm_status, metric, speed, ifmtu, ifmtu6,
1381 bandwidth, ll_type, hw_addr_len, hw_addr)
1383 (link_param_state,) = struct.unpack_from(cls._LP_STATE_FMT, rest)
1384 rest = rest[cls.LP_STATE_SIZE:]
1386 if link_param_state:
1387 link_params, rest = InterfaceLinkParams.parse(rest)
1391 return cls(ifname, ifindex, status, if_flags,
1392 ptm_enable, ptm_status, metric, speed, ifmtu, ifmtu6,
1393 bandwidth, ll_type, hw_addr_len, hw_addr,
1396 def serialize(self, version=_DEFAULT_VERSION):
1397 if self.ifname is None:
1398 # Case for sending message to Zebra
1401 if netaddr.valid_mac(self.hw_addr):
1404 hw_addr = addrconv.mac.text_to_bin(self.hw_addr)
1406 # Unknown hardware address
1407 hw_addr_len = len(self.hw_addr)
1408 hw_addr = self.hw_addr
1413 self.ifname.encode('ascii'), self.ifindex, self.status,
1414 self.if_flags, self.metric, self.ifmtu, self.ifmtu6,
1415 self.bandwidth, hw_addr_len) + hw_addr
1418 self._V3_HEADER_FMT,
1419 self.ifname.encode('ascii'), self.ifindex, self.status,
1420 self.if_flags, self.metric, self.ifmtu, self.ifmtu6,
1421 self.bandwidth, self.ll_type, hw_addr_len) + hw_addr
1423 if _is_frr_version_ge(_FRR_VERSION_3_0):
1425 self._V4_HEADER_FMT_3_0,
1426 self.ifname.encode('ascii'), self.ifindex, self.status,
1427 self.if_flags, self.ptm_enable, self.ptm_status,
1428 self.metric, self.speed, self.ifmtu, self.ifmtu6,
1429 self.bandwidth, self.ll_type, hw_addr_len) + hw_addr
1430 elif _is_frr_version_ge(_FRR_VERSION_2_0):
1432 self._V4_HEADER_FMT_2_0,
1433 self.ifname.encode('ascii'), self.ifindex, self.status,
1434 self.if_flags, self.ptm_enable, self.ptm_status,
1435 self.metric, self.ifmtu, self.ifmtu6,
1436 self.bandwidth, self.ll_type, hw_addr_len) + hw_addr
1439 'Unsupported FRRouting version: %s'
1440 % CONF['zapi'].frr_version)
1443 'Unsupported Zebra protocol version: %d'
1446 if isinstance(self.link_params, InterfaceLinkParams):
1447 buf += struct.pack(self._LP_STATE_FMT, True)
1448 buf += self.link_params.serialize()
1450 buf += struct.pack(self._LP_STATE_FMT, False)
1455 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ADD)
1456 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_ADD)
1457 class ZebraInterfaceAdd(_ZebraInterface):
1459 Message body class for ZEBRA_INTERFACE_ADD.
1463 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_DELETE)
1464 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_DELETE)
1465 class ZebraInterfaceDelete(_ZebraInterface):
1467 Message body class for ZEBRA_INTERFACE_DELETE.
1471 @six.add_metaclass(abc.ABCMeta)
1472 class _ZebraInterfaceAddress(_ZebraMessageBody):
1474 Base class for ZEBRA_INTERFACE_ADDRESS_ADD and
1475 ZEBRA_INTERFACE_ADDRESS_DELETE message body.
1477 # Zebra Interface Address Add/Delete message body:
1479 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1480 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1481 # | Interface index |
1482 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1483 # | IFC Flags | flags for connected address
1486 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1487 # | IPv4/v6 Prefix (Variable) |
1488 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1490 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1491 # | IPv4/v6 Destination Address (Variable) |
1492 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1493 _HEADER_FMT = '!IB' # ifindex, ifc_flags
1494 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
1496 def __init__(self, ifindex, ifc_flags, family, prefix, dest):
1497 super(_ZebraInterfaceAddress, self).__init__()
1498 self.ifindex = ifindex
1499 self.ifc_flags = ifc_flags
1500 self.family = family
1501 if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
1502 prefix = prefix.prefix
1503 self.prefix = prefix
1504 assert ip.valid_ipv4(dest) or ip.valid_ipv6(dest)
1508 def parse(cls, buf, version=_DEFAULT_VERSION):
1509 (ifindex, ifc_flags) = struct.unpack_from(cls._HEADER_FMT, buf)
1510 rest = buf[cls.HEADER_SIZE:]
1512 (family, prefix, rest) = _parse_zebra_family_prefix(rest)
1514 if socket.AF_INET == family:
1515 dest = addrconv.ipv4.bin_to_text(rest)
1516 elif socket.AF_INET6 == family:
1517 dest = addrconv.ipv6.bin_to_text(rest)
1519 raise struct.error('Unsupported family: %d' % family)
1521 return cls(ifindex, ifc_flags, family, prefix, dest)
1523 def serialize(self, version=_DEFAULT_VERSION):
1524 (self.family, # fixup
1525 body_bin) = _serialize_zebra_family_prefix(self.prefix)
1527 if ip.valid_ipv4(self.dest):
1528 body_bin += addrconv.ipv4.text_to_bin(self.dest)
1529 elif ip.valid_ipv6(self.prefix):
1530 body_bin += addrconv.ipv6.text_to_bin(self.dest)
1533 'Invalid destination address: %s' % self.dest)
1535 return struct.pack(self._HEADER_FMT,
1536 self.ifindex, self.ifc_flags) + body_bin
1539 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ADDRESS_ADD)
1540 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_ADDRESS_ADD)
1541 class ZebraInterfaceAddressAdd(_ZebraInterfaceAddress):
1543 Message body class for ZEBRA_INTERFACE_ADDRESS_ADD.
1547 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ADDRESS_DELETE)
1548 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_ADDRESS_DELETE)
1549 class ZebraInterfaceAddressDelete(_ZebraInterfaceAddress):
1551 Message body class for ZEBRA_INTERFACE_ADDRESS_DELETE.
1555 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_UP)
1556 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_UP)
1557 class ZebraInterfaceUp(_ZebraInterface):
1559 Message body class for ZEBRA_INTERFACE_UP.
1563 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_DOWN)
1564 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_DOWN)
1565 class ZebraInterfaceDown(_ZebraInterface):
1567 Message body class for ZEBRA_INTERFACE_DOWN.
1571 @six.add_metaclass(abc.ABCMeta)
1572 class _ZebraIPRoute(_ZebraMessageBody):
1574 Base class for ZEBRA_IPV4_ROUTE_* and ZEBRA_IPV6_ROUTE_*
1579 Zebra IPv4/IPv6 Route message have asymmetric structure.
1580 If the message sent from Zebra Daemon, set 'from_zebra=True' to
1581 create an instance of this class.
1583 # Zebra IPv4/IPv6 Route message body (Protocol Daemons -> Zebra Daemon):
1585 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1586 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1587 # | Route Type | Flags | Message |
1588 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1590 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1591 # | IPv4/v6 Prefix (Variable) |
1592 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1594 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1595 # | Nexthops (Variable) |
1596 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1598 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1600 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1602 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1604 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1606 # Zebra IPv4/IPv6 Route message body on FRRouting
1607 # (Protocol Daemons -> Zebra Daemon):
1609 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1610 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1611 # | Route Type | Instance |
1612 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1614 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1615 # | Message | SAFI |
1616 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1617 # | IPv4/v6 Prefix (Variable) |
1618 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1619 # | (IPv4/v6 Source Prefix): v4(FRRouting v3.0 or later) |
1620 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1622 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1623 # | Nexthops (Variable) |
1624 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1626 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1628 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1630 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1632 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1634 # Zebra IPv4/IPv6 Route message body (Zebra Daemon -> Protocol Daemons):
1636 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1637 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1638 # | Route Type | Flags | Message |
1639 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1640 # | IPv4/v6 Prefix (Variable) |
1641 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1643 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1644 # | (Nexthops (Variable)) |
1645 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1647 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1648 # | (Interface indexes) |
1649 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1651 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1653 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1655 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1657 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1659 # Zebra IPv4/IPv6 Route message body on FRRouting
1660 # (Zebra Daemon -> Protocol Daemons):
1662 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1663 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1664 # | Route Type | Instance |
1665 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1667 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1669 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1670 # | IPv4/v6 Prefix (Variable) |
1671 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1672 # | (IPv4/v6 Source Prefix): v4(FRRouting v3.0 or later) |
1673 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1675 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1676 # | (Nexthops (Variable)) |
1677 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1679 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1680 # | (Interface indexes) |
1681 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1683 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1685 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1687 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1688 _HEADER_FMT = '!BBB' # type, flags, message
1689 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
1690 _V4_HEADER_FMT = '!BHIB' # type, instance, flags, message
1691 V4_HEADER_SIZE = struct.calcsize(_V4_HEADER_FMT)
1692 _SAFI_FMT = '!H' # safi
1693 SAFI_SIZE = struct.calcsize(_SAFI_FMT)
1694 _NUM_FMT = '!B' # nexthop_num or ifindex_num
1695 NUM_SIZE = struct.calcsize(_NUM_FMT)
1696 _IFINDEX_FMT = '!I' # ifindex
1697 IFINDEX_SIZE = struct.calcsize(_IFINDEX_FMT)
1699 # API type specific constants
1700 _FAMILY = None # either socket.AF_INET or socket.AF_INET6
1702 def __init__(self, route_type, flags, message, safi=None,
1703 prefix=None, src_prefix=None,
1704 nexthops=None, ifindexes=None,
1705 distance=None, metric=None, mtu=None, tag=None,
1706 instance=None, from_zebra=False):
1707 super(_ZebraIPRoute, self).__init__()
1708 self.route_type = route_type
1709 self.instance = instance
1711 self.message = message
1713 # SAFI should be included if this message sent to Zebra.
1717 self.safi = safi or packet_safi.UNICAST
1719 assert prefix is not None
1720 if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
1721 prefix = prefix.prefix
1722 self.prefix = prefix
1724 if isinstance(src_prefix, (IPv4Prefix, IPv6Prefix)):
1725 src_prefix = src_prefix.prefix
1726 self.src_prefix = src_prefix
1728 # Nexthops should be a list of str representations of IP address
1729 # if this message sent from Zebra, otherwise a list of _Nexthop
1731 nexthops = nexthops or []
1733 for nexthop in nexthops:
1734 assert ip.valid_ipv4(nexthop) or ip.valid_ipv6(nexthop)
1736 for nexthop in nexthops:
1737 assert isinstance(nexthop, _NextHop)
1738 self.nexthops = nexthops
1740 # Interface indexes should be included if this message sent from
1743 ifindexes = ifindexes or []
1744 for ifindex in ifindexes:
1745 assert isinstance(ifindex, six.integer_types)
1746 self.ifindexes = ifindexes
1748 self.ifindexes = None
1750 self.distance = distance
1751 self.metric = metric
1755 # is this message sent from Zebra message or not.
1756 self.from_zebra = from_zebra
1759 def _parse_message_option(cls, message, flag, fmt, buf):
1761 (option,) = struct.unpack_from(fmt, buf)
1762 return option, buf[struct.calcsize(fmt):]
1767 def _parse_impl(cls, buf, version=_DEFAULT_VERSION, from_zebra=False):
1770 (route_type, flags, message,) = struct.unpack_from(
1771 cls._HEADER_FMT, buf)
1772 rest = buf[cls.HEADER_SIZE:]
1774 (route_type, instance, flags, message,) = struct.unpack_from(
1775 cls._V4_HEADER_FMT, buf)
1776 rest = buf[cls.V4_HEADER_SIZE:]
1779 'Unsupported Zebra protocol version: %d'
1785 (safi,) = struct.unpack_from(cls._SAFI_FMT, rest)
1786 rest = rest[cls.SAFI_SIZE:]
1788 prefix, rest = _parse_ip_prefix(cls._FAMILY, rest)
1791 if version == 4 and message & FRR_ZAPI_MESSAGE_SRCPFX:
1792 src_prefix, rest = _parse_ip_prefix(cls._FAMILY, rest)
1794 if from_zebra and message & ZAPI_MESSAGE_NEXTHOP:
1796 (nexthop_num,) = struct.unpack_from(cls._NUM_FMT, rest)
1797 rest = rest[cls.NUM_SIZE:]
1798 if cls._FAMILY == socket.AF_INET:
1799 for _ in range(nexthop_num):
1800 nexthop = addrconv.ipv4.bin_to_text(rest[:4])
1801 nexthops.append(nexthop)
1803 else: # cls._FAMILY == socket.AF_INET6:
1804 for _ in range(nexthop_num):
1805 nexthop = addrconv.ipv6.bin_to_text(rest[:16])
1806 nexthops.append(nexthop)
1809 nexthops, rest = _parse_nexthops(rest, version)
1812 if from_zebra and message & ZAPI_MESSAGE_IFINDEX:
1813 (ifindex_num,) = struct.unpack_from(cls._NUM_FMT, rest)
1814 rest = rest[cls.NUM_SIZE:]
1815 for _ in range(ifindex_num):
1816 (ifindex,) = struct.unpack_from(cls._IFINDEX_FMT, rest)
1817 ifindexes.append(ifindex)
1818 rest = rest[cls.IFINDEX_SIZE:]
1821 distance, rest = cls._parse_message_option(
1822 message, ZAPI_MESSAGE_DISTANCE, '!B', rest)
1823 metric, rest = cls._parse_message_option(
1824 message, ZAPI_MESSAGE_METRIC, '!I', rest)
1825 mtu, rest = cls._parse_message_option(
1826 message, ZAPI_MESSAGE_MTU, '!I', rest)
1827 tag, rest = cls._parse_message_option(
1828 message, ZAPI_MESSAGE_TAG, '!I', rest)
1830 distance, rest = cls._parse_message_option(
1831 message, FRR_ZAPI_MESSAGE_DISTANCE, '!B', rest)
1832 metric, rest = cls._parse_message_option(
1833 message, FRR_ZAPI_MESSAGE_METRIC, '!I', rest)
1834 tag, rest = cls._parse_message_option(
1835 message, FRR_ZAPI_MESSAGE_TAG, '!I', rest)
1836 mtu, rest = cls._parse_message_option(
1837 message, FRR_ZAPI_MESSAGE_MTU, '!I', rest)
1840 'Unsupported Zebra protocol version: %d'
1843 return cls(route_type, flags, message, safi, prefix, src_prefix,
1844 nexthops, ifindexes,
1845 distance, metric, mtu, tag,
1846 instance, from_zebra=from_zebra)
1849 def parse(cls, buf, version=_DEFAULT_VERSION):
1850 return cls._parse_impl(buf, version=version)
1853 def parse_from_zebra(cls, buf, version=_DEFAULT_VERSION):
1854 return cls._parse_impl(buf, version=version, from_zebra=True)
1856 def _serialize_message_option(self, option, flag, fmt):
1861 self.message |= flag
1863 return struct.pack(fmt, option)
1865 def serialize(self, version=_DEFAULT_VERSION):
1866 prefix = _serialize_ip_prefix(self.prefix)
1867 if version == 4 and self.src_prefix:
1868 self.message |= FRR_ZAPI_MESSAGE_SRCPFX # fixup
1869 prefix += _serialize_ip_prefix(self.src_prefix)
1872 if self.from_zebra and self.nexthops:
1873 self.message |= ZAPI_MESSAGE_NEXTHOP # fixup
1874 nexthops += struct.pack(self._NUM_FMT, len(self.nexthops))
1875 for nexthop in self.nexthops:
1876 nexthops += ip.text_to_bin(nexthop)
1878 self.message |= ZAPI_MESSAGE_NEXTHOP # fixup
1879 nexthops = _serialize_nexthops(self.nexthops, version=version)
1882 if self.ifindexes and self.from_zebra:
1883 self.message |= ZAPI_MESSAGE_IFINDEX # fixup
1884 ifindexes += struct.pack(self._NUM_FMT, len(self.ifindexes))
1885 for ifindex in self.ifindexes:
1886 ifindexes += struct.pack(self._IFINDEX_FMT, ifindex)
1889 options = self._serialize_message_option(
1890 self.distance, ZAPI_MESSAGE_DISTANCE, '!B')
1891 options += self._serialize_message_option(
1892 self.metric, ZAPI_MESSAGE_METRIC, '!I')
1893 options += self._serialize_message_option(
1894 self.mtu, ZAPI_MESSAGE_MTU, '!I')
1895 options += self._serialize_message_option(
1896 self.tag, ZAPI_MESSAGE_TAG, '!I')
1897 header = struct.pack(
1899 self.route_type, self.flags, self.message)
1901 options = self._serialize_message_option(
1902 self.distance, FRR_ZAPI_MESSAGE_DISTANCE, '!B')
1903 options += self._serialize_message_option(
1904 self.metric, FRR_ZAPI_MESSAGE_METRIC, '!I')
1905 options += self._serialize_message_option(
1906 self.tag, FRR_ZAPI_MESSAGE_TAG, '!I')
1907 options += self._serialize_message_option(
1908 self.mtu, FRR_ZAPI_MESSAGE_MTU, '!I')
1909 header = struct.pack(
1910 self._V4_HEADER_FMT,
1911 self.route_type, self.instance, self.flags, self.message)
1914 'Unsupported Zebra protocol version: %d'
1917 if not self.from_zebra:
1918 header += struct.pack(self._SAFI_FMT, self.safi)
1920 return header + prefix + nexthops + ifindexes + options
1923 class _ZebraIPv4Route(_ZebraIPRoute):
1925 Base class for ZEBRA_IPV4_ROUTE_* message body.
1927 _FAMILY = socket.AF_INET
1930 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_ROUTE_ADD)
1931 @_ZebraMessageBody.register_type(ZEBRA_IPV4_ROUTE_ADD)
1932 class ZebraIPv4RouteAdd(_ZebraIPv4Route):
1934 Message body class for ZEBRA_IPV4_ROUTE_ADD.
1938 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_ROUTE_DELETE)
1939 @_ZebraMessageBody.register_type(ZEBRA_IPV4_ROUTE_DELETE)
1940 class ZebraIPv4RouteDelete(_ZebraIPv4Route):
1942 Message body class for ZEBRA_IPV4_ROUTE_DELETE.
1946 class _ZebraIPv6Route(_ZebraIPRoute):
1948 Base class for ZEBRA_IPV6_ROUTE_* message body.
1950 _FAMILY = socket.AF_INET6
1953 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_ROUTE_ADD)
1954 @_ZebraMessageBody.register_type(ZEBRA_IPV6_ROUTE_ADD)
1955 class ZebraIPv6RouteAdd(_ZebraIPv6Route):
1957 Message body class for ZEBRA_IPV6_ROUTE_ADD.
1961 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_ROUTE_DELETE)
1962 @_ZebraMessageBody.register_type(ZEBRA_IPV6_ROUTE_DELETE)
1963 class ZebraIPv6RouteDelete(_ZebraIPv6Route):
1965 Message body class for ZEBRA_IPV6_ROUTE_DELETE.
1969 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD)
1970 class ZebraIPv4RouteIPv6NexthopAdd(_ZebraIPv4Route):
1972 Message body class for FRR_ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD.
1976 @six.add_metaclass(abc.ABCMeta)
1977 class _ZebraRedistribute(_ZebraMessageBody):
1979 Base class for ZEBRA_REDISTRIBUTE_ADD and ZEBRA_REDISTRIBUTE_DELETE
1982 # Zebra Redistribute message body:
1984 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1985 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1989 # Zebra Redistribute message body on FRRouting:
1991 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1992 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1993 # | AFI | Route Type | Instance |
1994 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+-+-+-+-+-++-+-+-+-+-+-+
1995 _HEADER_FMT = '!B' # route_type
1996 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
1997 _V4_HEADER_FMT = '!BBH' # afi, route_type, instance
1998 V4_HEADER_SIZE = struct.calcsize(_V4_HEADER_FMT)
2000 def __init__(self, route_type, afi=None, instance=None):
2001 super(_ZebraRedistribute, self).__init__()
2003 self.route_type = route_type
2004 self.instance = instance
2007 def parse(cls, buf, version=_DEFAULT_VERSION):
2011 (route_type,) = struct.unpack_from(cls._HEADER_FMT, buf)
2014 instance) = struct.unpack_from(cls._V4_HEADER_FMT, buf)
2017 'Unsupported Zebra protocol version: %d'
2020 return cls(route_type, afi, instance)
2022 def serialize(self, version=_DEFAULT_VERSION):
2024 return struct.pack(self._HEADER_FMT, self.route_type)
2026 return struct.pack(self._V4_HEADER_FMT,
2027 self.afi, self.route_type, self.instance)
2030 'Unsupported Zebra protocol version: %d'
2034 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_ADD)
2035 @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_ADD)
2036 class ZebraRedistributeAdd(_ZebraRedistribute):
2038 Message body class for ZEBRA_REDISTRIBUTE_ADD.
2042 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_DELETE)
2043 @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_DELETE)
2044 class ZebraRedistributeDelete(_ZebraRedistribute):
2046 Message body class for ZEBRA_REDISTRIBUTE_DELETE.
2050 @six.add_metaclass(abc.ABCMeta)
2051 class _ZebraRedistributeDefault(_ZebraMessageBody):
2053 Base class for ZEBRA_REDISTRIBUTE_DEFAULT_ADD and
2054 ZEBRA_REDISTRIBUTE_DEFAULT_DELETE message body.
2058 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_DEFAULT_ADD)
2059 @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_DEFAULT_ADD)
2060 class ZebraRedistributeDefaultAdd(_ZebraRedistribute):
2062 Message body class for ZEBRA_REDISTRIBUTE_DEFAULT_ADD.
2066 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_DEFAULT_DELETE)
2067 @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE)
2068 class ZebraRedistributeDefaultDelete(_ZebraRedistribute):
2070 Message body class for ZEBRA_REDISTRIBUTE_DEFAULT_DELETE.
2074 @six.add_metaclass(abc.ABCMeta)
2075 class _ZebraIPNexthopLookup(_ZebraMessageBody):
2077 Base class for ZEBRA_IPV4_NEXTHOP_LOOKUP and
2078 ZEBRA_IPV6_NEXTHOP_LOOKUP message body.
2080 # Zebra IPv4/v6 Nexthop Lookup message body:
2082 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2083 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2084 # | IPv4/v6 address |
2085 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2087 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2089 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2090 # | Nexthops (Variable) |
2091 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2092 _METRIC_FMT = '!I' # metric
2093 METRIC_SIZE = struct.calcsize(_METRIC_FMT)
2095 # Message type specific constants
2096 ADDR_CLS = None # either addrconv.ipv4 or addrconv.ipv6
2097 ADDR_LEN = None # IP address length in bytes
2099 def __init__(self, addr, metric=None, nexthops=None):
2100 super(_ZebraIPNexthopLookup, self).__init__()
2101 assert ip.valid_ipv4(addr) or ip.valid_ipv6(addr)
2103 self.metric = metric
2104 nexthops = nexthops or []
2105 for nexthop in nexthops:
2106 assert isinstance(nexthop, _NextHop)
2107 self.nexthops = nexthops
2110 def parse(cls, buf, version=_DEFAULT_VERSION):
2111 addr = cls.ADDR_CLS.bin_to_text(buf[:cls.ADDR_LEN])
2112 rest = buf[cls.ADDR_LEN:]
2116 # Note: Case for ZEBRA_IPV4_NEXTHOP_LOOKUP request
2117 (metric,) = struct.unpack_from(cls._METRIC_FMT, rest)
2118 rest = rest[cls.METRIC_SIZE:]
2122 nexthops, rest = _parse_nexthops(rest, version)
2124 return cls(addr, metric, nexthops)
2126 def serialize(self, version=_DEFAULT_VERSION):
2127 buf = self.ADDR_CLS.text_to_bin(self.addr)
2129 if self.metric is None:
2132 buf += struct.pack(self._METRIC_FMT, self.metric)
2134 return buf + _serialize_nexthops(self.nexthops, version=version)
2137 @_ZebraMessageBody.register_type(ZEBRA_IPV4_NEXTHOP_LOOKUP)
2138 class ZebraIPv4NexthopLookup(_ZebraIPNexthopLookup):
2140 Message body class for ZEBRA_IPV4_NEXTHOP_LOOKUP.
2142 ADDR_CLS = addrconv.ipv4
2146 @_ZebraMessageBody.register_type(ZEBRA_IPV6_NEXTHOP_LOOKUP)
2147 class ZebraIPv6NexthopLookup(_ZebraIPNexthopLookup):
2149 Message body class for ZEBRA_IPV6_NEXTHOP_LOOKUP.
2151 ADDR_CLS = addrconv.ipv6
2155 @six.add_metaclass(abc.ABCMeta)
2156 class _ZebraIPImportLookup(_ZebraMessageBody):
2158 Base class for ZEBRA_IPV4_IMPORT_LOOKUP and
2159 ZEBRA_IPV6_IMPORT_LOOKUP message body.
2163 Zebra IPv4/v6 Import Lookup message have asymmetric structure.
2164 If the message sent from Zebra Daemon, set 'from_zebra=True' to
2165 create an instance of this class.
2167 # Zebra IPv4/v6 Import Lookup message body
2168 # (Protocol Daemons -> Zebra Daemon):
2170 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2171 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2173 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2174 # | IPv4/v6 Prefix (4 bytes or 16 bytes) |
2175 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2177 # Zebra IPv4/v6 Import Lookup message body
2178 # (Zebra Daemons -> Protocol Daemon):
2180 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2181 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2182 # | IPv4/v6 Prefix (4 bytes or 16 bytes) |
2183 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2185 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2187 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2188 # | Nexthops (Variable) |
2189 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2190 _PREFIX_LEN_FMT = '!B' # prefix_len
2191 PREFIX_LEN_SIZE = struct.calcsize(_PREFIX_LEN_FMT)
2192 _METRIC_FMT = '!I' # metric
2193 METRIC_SIZE = struct.calcsize(_METRIC_FMT)
2195 # Message type specific constants
2196 PREFIX_CLS = None # either addrconv.ipv4 or addrconv.ipv6
2197 PREFIX_LEN = None # IP prefix length in bytes
2199 def __init__(self, prefix, metric=None, nexthops=None,
2201 super(_ZebraIPImportLookup, self).__init__()
2203 assert ip.valid_ipv4(prefix) or ip.valid_ipv6(prefix)
2205 if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
2206 prefix = prefix.prefix
2208 assert ip.valid_ipv4(prefix) or ip.valid_ipv6(prefix)
2209 self.prefix = prefix
2210 self.metric = metric
2211 nexthops = nexthops or []
2212 for nexthop in nexthops:
2213 assert isinstance(nexthop, _NextHop)
2214 self.nexthops = nexthops
2215 self.from_zebra = from_zebra
2218 def parse_impl(cls, buf, version=_DEFAULT_VERSION, from_zebra=False):
2220 (prefix_len,) = struct.unpack_from(cls._PREFIX_LEN_FMT, buf)
2221 rest = buf[cls.PREFIX_LEN_SIZE:]
2222 prefix = cls.PREFIX_CLS.bin_to_text(rest[:cls.PREFIX_LEN])
2223 return cls('%s/%d' % (prefix, prefix_len), from_zebra=False)
2225 prefix = cls.PREFIX_CLS.bin_to_text(buf[:cls.PREFIX_LEN])
2228 (metric,) = struct.unpack_from(cls._METRIC_FMT, rest)
2229 rest = rest[cls.METRIC_SIZE:]
2231 nexthops, rest = _parse_nexthops(rest, version)
2233 return cls(prefix, metric, nexthops, from_zebra=True)
2236 def parse(cls, buf, version=_DEFAULT_VERSION):
2237 return cls.parse_impl(buf, version=version, from_zebra=False)
2240 def parse_from_zebra(cls, buf, version=_DEFAULT_VERSION):
2241 return cls.parse_impl(buf, version=version, from_zebra=True)
2243 def serialize(self, version=_DEFAULT_VERSION):
2244 if not self.from_zebra:
2245 if ip.valid_ipv4(self.prefix) or ip.valid_ipv6(self.prefix):
2246 prefix, prefix_len = self.prefix.split('/')
2248 self._PREFIX_LEN_FMT,
2249 int(prefix_len)) + self.PREFIX_CLS.text_to_bin(prefix)
2251 raise ValueError('Invalid prefix: %s' % self.prefix)
2253 if ip.valid_ipv4(self.prefix) or ip.valid_ipv6(self.prefix):
2254 buf = self.PREFIX_CLS.text_to_bin(self.prefix)
2256 raise ValueError('Invalid prefix: %s' % self.prefix)
2258 buf += struct.pack(self._METRIC_FMT, self.metric)
2260 return buf + _serialize_nexthops(self.nexthops, version=version)
2263 @_ZebraMessageBody.register_type(ZEBRA_IPV4_IMPORT_LOOKUP)
2264 class ZebraIPv4ImportLookup(_ZebraIPImportLookup):
2266 Message body class for ZEBRA_IPV4_IMPORT_LOOKUP.
2268 PREFIX_CLS = addrconv.ipv4
2272 @_ZebraMessageBody.register_type(ZEBRA_IPV6_IMPORT_LOOKUP)
2273 class ZebraIPv6ImportLookup(_ZebraIPImportLookup):
2275 Message body class for ZEBRA_IPV6_IMPORT_LOOKUP.
2277 PREFIX_CLS = addrconv.ipv6
2281 # Note: Not implemented in quagga/zebra/zserv.c
2282 # @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_RENAME)
2283 # class ZebraInterfaceRename(_ZebraMessageBody):
2286 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_ROUTER_ID_ADD)
2287 @_ZebraMessageBody.register_type(ZEBRA_ROUTER_ID_ADD)
2288 class ZebraRouterIDAdd(_ZebraMessageBody):
2290 Message body class for ZEBRA_ROUTER_ID_ADD.
2294 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_ROUTER_ID_DELETE)
2295 @_ZebraMessageBody.register_type(ZEBRA_ROUTER_ID_DELETE)
2296 class ZebraRouterIDDelete(_ZebraMessageBody):
2298 Message body class for ZEBRA_ROUTER_ID_DELETE.
2302 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_ROUTER_ID_UPDATE)
2303 @_ZebraMessageBody.register_type(ZEBRA_ROUTER_ID_UPDATE)
2304 class ZebraRouterIDUpdate(_ZebraMessageBody):
2306 Message body class for ZEBRA_ROUTER_ID_UPDATE.
2308 # Zebra Router ID Update message body:
2310 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2311 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2313 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2314 # | IPv4/v6 prefix |
2315 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2319 def __init__(self, family, prefix):
2320 super(ZebraRouterIDUpdate, self).__init__()
2321 self.family = family
2322 if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
2323 prefix = prefix.prefix
2324 self.prefix = prefix
2327 def parse(cls, buf, version=_DEFAULT_VERSION):
2328 (family, prefix, _) = _parse_zebra_family_prefix(buf)
2330 return cls(family, prefix)
2332 def serialize(self, version=_DEFAULT_VERSION):
2333 (self.family, # fixup
2334 buf) = _serialize_zebra_family_prefix(self.prefix)
2339 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_HELLO)
2340 @_ZebraMessageBody.register_type(ZEBRA_HELLO)
2341 class ZebraHello(_ZebraMessageBody):
2343 Message body class for ZEBRA_HELLO.
2345 # Zebra Hello message body:
2347 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2348 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2349 # | Route Type | (Instance): v4(FRRouting) |
2350 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2351 _HEADER_FMT = '!B' # route_type
2352 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
2353 _V4_HEADER_FMT = '!BH' # route_type, instance
2354 V4_HEADER_SIZE = struct.calcsize(_V4_HEADER_FMT)
2356 def __init__(self, route_type, instance=None):
2357 super(ZebraHello, self).__init__()
2358 self.route_type = route_type
2359 self.instance = instance
2362 def parse(cls, buf, version=_DEFAULT_VERSION):
2365 (route_type,) = struct.unpack_from(cls._HEADER_FMT, buf)
2368 instance) = struct.unpack_from(cls._V4_HEADER_FMT, buf)
2371 'Unsupported Zebra protocol version: %d'
2374 return cls(route_type, instance)
2376 def serialize(self, version=_DEFAULT_VERSION):
2378 return struct.pack(self._HEADER_FMT, self.route_type)
2380 return struct.pack(self._V4_HEADER_FMT,
2381 self.route_type, self.instance)
2384 'Unsupported Zebra protocol version: %d'
2388 @six.add_metaclass(abc.ABCMeta)
2389 class _ZebraIPNexthopLookupMRib(_ZebraMessageBody):
2391 Base class for ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB (and
2392 ZEBRA_IPV6_NEXTHOP_LOOKUP_MRIB) message body.
2394 # Zebra IPv4/v6 Nexthop Lookup MRIB message body:
2396 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2397 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2398 # | IPv4/v6 address |
2399 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2401 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2403 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2405 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2406 # | Nexthops (Variable) |
2407 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2408 _DISTANCE_METRIC_FMT = '!BI' # distance, metric
2409 DISTANCE_METRIC_SIZE = struct.calcsize(_DISTANCE_METRIC_FMT)
2411 # Message type specific constants
2412 ADDR_CLS = None # either addrconv.ipv4 or addrconv.ipv6
2413 ADDR_LEN = None # IP address length in bytes
2415 def __init__(self, addr, distance=None, metric=None, nexthops=None):
2416 super(_ZebraIPNexthopLookupMRib, self).__init__()
2417 assert ip.valid_ipv4(addr) or ip.valid_ipv6(addr)
2419 self.distance = distance
2420 self.metric = metric
2421 nexthops = nexthops or []
2422 for nexthop in nexthops:
2423 assert isinstance(nexthop, _NextHop)
2424 self.nexthops = nexthops
2427 def parse(cls, buf, version=_DEFAULT_VERSION):
2428 addr = cls.ADDR_CLS.bin_to_text(buf[:cls.ADDR_LEN])
2429 rest = buf[cls.ADDR_LEN:]
2435 metric) = struct.unpack_from(cls._DISTANCE_METRIC_FMT, rest)
2436 rest = rest[cls.DISTANCE_METRIC_SIZE:]
2438 nexthops, rest = _parse_nexthops(rest, version)
2440 return cls(addr, distance, metric, nexthops)
2442 def serialize(self, version=_DEFAULT_VERSION):
2443 buf = self.ADDR_CLS.text_to_bin(self.addr)
2445 if self.distance is None or self.metric is None:
2449 self._DISTANCE_METRIC_FMT, self.distance, self.metric)
2451 return buf + _serialize_nexthops(self.nexthops, version=version)
2454 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB)
2455 @_ZebraMessageBody.register_type(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB)
2456 class ZebraIPv4NexthopLookupMRib(_ZebraIPNexthopLookupMRib):
2458 Message body class for ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB.
2460 ADDR_CLS = addrconv.ipv4
2464 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_VRF_UNREGISTER)
2465 @_ZebraMessageBody.register_type(ZEBRA_VRF_UNREGISTER)
2466 class ZebraVrfUnregister(_ZebraMessageBody):
2468 Message body class for ZEBRA_VRF_UNREGISTER.
2472 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_LINK_PARAMS)
2473 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_LINK_PARAMS)
2474 class ZebraInterfaceLinkParams(_ZebraMessageBody):
2476 Message body class for ZEBRA_INTERFACE_LINK_PARAMS.
2478 # Zebra Interface Link Parameters message body:
2480 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2481 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2482 # | Interface Index |
2483 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2484 # | Interface Link Parameters |
2485 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2486 _HEADER_FMT = '!I' # ifindex
2487 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
2488 # See InterfaceLinkParams class for Interface Link Parameters structure
2490 def __init__(self, ifindex, link_params):
2491 super(ZebraInterfaceLinkParams, self).__init__()
2492 self.ifindex = ifindex
2493 assert isinstance(link_params, InterfaceLinkParams)
2494 self.link_params = link_params
2497 def parse(cls, buf, version=_DEFAULT_VERSION):
2498 (ifindex,) = struct.unpack_from(cls._HEADER_FMT, buf)
2499 rest = buf[cls.HEADER_SIZE:]
2501 link_params, rest = InterfaceLinkParams.parse(rest)
2503 return cls(ifindex, link_params)
2505 def serialize(self, version=_DEFAULT_VERSION):
2506 buf = struct.pack(self._HEADER_FMT, self.ifindex)
2508 return buf + self.link_params.serialize()
2511 class _ZebraNexthopRegister(_ZebraMessageBody):
2513 Base class for ZEBRA_NEXTHOP_REGISTER and ZEBRA_NEXTHOP_UNREGISTER
2516 # Zebra Nexthop Register message body:
2517 # (Repeat of RegisteredNexthop class)
2519 def __init__(self, nexthops):
2520 super(_ZebraNexthopRegister, self).__init__()
2521 nexthops = nexthops or []
2522 for nexthop in nexthops:
2523 assert isinstance(nexthop, RegisteredNexthop)
2524 self.nexthops = nexthops
2527 def parse(cls, buf, version=_DEFAULT_VERSION):
2530 nexthop, buf = RegisteredNexthop.parse(buf)
2531 nexthops.append(nexthop)
2533 return cls(nexthops)
2535 def serialize(self, version=_DEFAULT_VERSION):
2537 for nexthop in self.nexthops:
2538 buf += nexthop.serialize()
2543 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_NEXTHOP_REGISTER)
2544 @_ZebraMessageBody.register_type(ZEBRA_NEXTHOP_REGISTER)
2545 class ZebraNexthopRegister(_ZebraNexthopRegister):
2547 Message body class for ZEBRA_NEXTHOP_REGISTER.
2551 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_NEXTHOP_UNREGISTER)
2552 @_ZebraMessageBody.register_type(ZEBRA_NEXTHOP_UNREGISTER)
2553 class ZebraNexthopUnregister(_ZebraNexthopRegister):
2555 Message body class for ZEBRA_NEXTHOP_UNREGISTER.
2559 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_NEXTHOP_UPDATE)
2560 @_ZebraMessageBody.register_type(ZEBRA_NEXTHOP_UPDATE)
2561 class ZebraNexthopUpdate(_ZebraMessageBody):
2563 Message body class for ZEBRA_NEXTHOP_UPDATE.
2565 # Zebra IPv4/v6 Nexthop Update message body:
2567 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2568 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2570 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2571 # | IPv4/v6 prefix |
2572 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2573 # | (Distance) | v4(FRRouting v3.0 or later)
2574 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2576 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2578 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2579 # | Nexthops (Variable) |
2580 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2581 _FAMILY_FMT = '!H' # family
2582 FAMILY_SIZE = struct.calcsize(_FAMILY_FMT)
2583 _DISTANCE_FMT = '!B' # metric
2584 DISTANCE_SIZE = struct.calcsize(_DISTANCE_FMT)
2585 _METRIC_FMT = '!I' # metric
2586 METRIC_SIZE = struct.calcsize(_METRIC_FMT)
2588 def __init__(self, family, prefix, distance=None, metric=None,
2590 super(ZebraNexthopUpdate, self).__init__()
2591 self.family = family
2592 if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
2593 prefix = prefix.prefix
2594 self.prefix = prefix
2595 if _is_frr_version_ge(_FRR_VERSION_3_0):
2596 assert distance is not None
2597 self.distance = distance
2598 assert metric is not None
2599 self.metric = metric
2600 nexthops = nexthops or []
2601 for nexthop in nexthops:
2602 assert isinstance(nexthop, _NextHop)
2603 self.nexthops = nexthops
2606 def parse(cls, buf, version=_DEFAULT_VERSION):
2607 (family,) = struct.unpack_from(cls._FAMILY_FMT, buf)
2608 rest = buf[cls.FAMILY_SIZE:]
2610 prefix, rest = _parse_ip_prefix(family, rest)
2613 if _is_frr_version_ge(_FRR_VERSION_3_0):
2614 (distance,) = struct.unpack_from(cls._DISTANCE_FMT, rest)
2615 rest = rest[cls.DISTANCE_SIZE:]
2617 (metric,) = struct.unpack_from(cls._METRIC_FMT, rest)
2618 rest = rest[cls.METRIC_SIZE:]
2620 nexthops, rest = _parse_nexthops(rest, version)
2622 return cls(family, prefix, distance, metric, nexthops)
2624 def serialize(self, version=_DEFAULT_VERSION):
2626 if ip.valid_ipv4(self.prefix):
2627 self.family = socket.AF_INET
2628 elif ip.valid_ipv6(self.prefix):
2629 self.family = socket.AF_INET6
2631 raise ValueError('Invalid prefix: %s' % self.prefix)
2633 buf = struct.pack(self._FAMILY_FMT, self.family)
2635 buf += _serialize_ip_prefix(self.prefix)
2637 if _is_frr_version_ge(_FRR_VERSION_3_0):
2638 buf += struct.pack(self._DISTANCE_FMT, self.distance)
2640 buf += struct.pack(self._METRIC_FMT, self.metric)
2642 return buf + _serialize_nexthops(self.nexthops, version=version)
2645 class _ZebraInterfaceNbrAddress(_ZebraMessageBody):
2647 Base class for FRR_ZEBRA_INTERFACE_NBR_ADDRESS_* message body.
2649 # Zebra Interface Neighbor Address message body:
2651 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2652 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2653 # | Interface index |
2654 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2656 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2657 # | IPv4/v6 prefix |
2658 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2661 _HEADER_FMT = '!I' # ifindex
2662 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
2664 def __init__(self, ifindex, family, prefix):
2665 super(_ZebraInterfaceNbrAddress, self).__init__()
2666 self.ifindex = ifindex
2667 self.family = family
2668 if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
2669 prefix = prefix.prefix
2670 self.prefix = prefix
2673 def parse(cls, buf, version=_DEFAULT_VERSION):
2674 (ifindex,) = struct.unpack_from(cls._HEADER_FMT, buf)
2675 rest = buf[cls.HEADER_SIZE:]
2677 (family, prefix, _) = _parse_zebra_family_prefix(rest)
2679 return cls(ifindex, family, prefix)
2681 def serialize(self, version=_DEFAULT_VERSION):
2682 (self.family, # fixup
2683 body_bin) = _serialize_zebra_family_prefix(self.prefix)
2685 return struct.pack(self._HEADER_FMT, self.ifindex) + body_bin
2688 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_NBR_ADDRESS_ADD)
2689 class ZebraInterfaceNbrAddressAdd(_ZebraInterfaceNbrAddress):
2691 Message body class for FRR_ZEBRA_INTERFACE_NBR_ADDRESS_ADD.
2695 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_NBR_ADDRESS_DELETE)
2696 class ZebraInterfaceNbrAddressDelete(_ZebraInterfaceNbrAddress):
2698 Message body class for FRR_ZEBRA_INTERFACE_NBR_ADDRESS_DELETE.
2702 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE)
2703 class ZebraInterfaceBfdDestinationUpdate(_ZebraMessageBody):
2705 Message body class for FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE.
2707 # Zebra Interface BFD Destination Update message body:
2709 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2710 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2711 # | Interface index |
2712 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2714 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2715 # | Dst IPv4/v6 prefix |
2716 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2722 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2723 # | Source IPv4/v6 prefix |
2724 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2727 _HEADER_FMT = '!I' # ifindex
2728 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
2729 _STATUS_FMT = '!B' # status
2730 STATUS_SIZE = struct.calcsize(_STATUS_FMT)
2732 def __init__(self, ifindex, dst_family, dst_prefix, status,
2733 src_family, src_prefix):
2734 super(ZebraInterfaceBfdDestinationUpdate, self).__init__()
2735 self.ifindex = ifindex
2736 self.dst_family = dst_family
2737 if isinstance(dst_prefix, (IPv4Prefix, IPv6Prefix)):
2738 dst_prefix = dst_prefix.prefix
2739 self.dst_prefix = dst_prefix
2740 self.status = status
2741 self.src_family = src_family
2742 if isinstance(src_prefix, (IPv4Prefix, IPv6Prefix)):
2743 src_prefix = src_prefix.prefix
2744 self.src_prefix = src_prefix
2747 def parse(cls, buf, version=_DEFAULT_VERSION):
2748 (ifindex,) = struct.unpack_from(cls._HEADER_FMT, buf)
2749 rest = buf[cls.HEADER_SIZE:]
2751 (dst_family, dst_prefix,
2752 rest) = _parse_zebra_family_prefix(rest)
2754 (status,) = struct.unpack_from(cls._STATUS_FMT, rest)
2755 rest = rest[cls.STATUS_SIZE:]
2757 (src_family, src_prefix,
2758 _) = _parse_zebra_family_prefix(rest)
2760 return cls(ifindex, dst_family, dst_prefix, status,
2761 src_family, src_prefix)
2763 def serialize(self, version=_DEFAULT_VERSION):
2764 (self.dst_family, # fixup
2765 dst_bin) = _serialize_zebra_family_prefix(self.dst_prefix)
2767 status_bin = struct.pack(
2768 self._STATUS_FMT, self.status)
2770 (self.src_family, # fixup
2771 src_bin) = _serialize_zebra_family_prefix(self.src_prefix)
2775 self.ifindex) + dst_bin + status_bin + src_bin
2778 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IMPORT_ROUTE_REGISTER)
2779 class ZebraImportRouteRegister(_ZebraNexthopRegister):
2781 Message body class for FRR_ZEBRA_IMPORT_ROUTE_REGISTER.
2785 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IMPORT_ROUTE_UNREGISTER)
2786 class ZebraImportRouteUnregister(_ZebraNexthopRegister):
2788 Message body class for FRR_ZEBRA_IMPORT_ROUTE_UNREGISTER.
2792 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IMPORT_CHECK_UPDATE)
2793 class ZebraImportCheckUpdate(ZebraNexthopUpdate):
2795 Message body class for FRR_ZEBRA_IMPORT_CHECK_UPDATE.
2799 class _ZebraBfdDestination(_ZebraMessageBody):
2801 Base class for FRR_ZEBRA_BFD_DEST_REGISTER and
2802 FRR_ZEBRA_BFD_DEST_UPDATE message body.
2804 # Zebra BFD Destination message body:
2806 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2807 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2809 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2810 # | Destination Family |
2811 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2812 # | Destination IPv4/v6 prefix (4 bytes or 16 bytes) |
2813 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2815 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2817 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2821 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2823 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2824 # | Source IPv4/v6 prefix (4 bytes or 16 bytes) |
2825 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2826 # | (MultiHopCnt) | if Multi Hop enabled
2828 # | (IFName Len) | if Multi Hop disabled
2829 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2830 # | (Interface Name (Variable)) if Multi Hop disabled |
2831 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2832 _HEADER_FMT = '!I' # pid
2833 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
2835 FAMILY_SIZE = struct.calcsize(_FAMILY_FMT)
2836 _BODY_FMT = '!IIBB' # min_rx_timer, min_tx_timer, detect_mult, multi_hop
2837 BODY_SIZE = struct.calcsize(_BODY_FMT)
2838 _FOOTER_FMT = '!B' # multi_hop_count or ifname_len
2839 FOOTER_SIZE = struct.calcsize(_FOOTER_FMT)
2841 def __init__(self, pid, dst_family, dst_prefix,
2842 min_rx_timer, min_tx_timer, detect_mult,
2843 multi_hop, src_family, src_prefix,
2844 multi_hop_count=None, ifname=None):
2845 super(_ZebraBfdDestination, self).__init__()
2847 self.dst_family = dst_family
2848 assert ip.valid_ipv4(dst_prefix) or ip.valid_ipv6(dst_prefix)
2849 self.dst_prefix = dst_prefix
2850 self.min_rx_timer = min_rx_timer
2851 self.min_tx_timer = min_tx_timer
2852 self.detect_mult = detect_mult
2853 self.multi_hop = multi_hop
2854 self.src_family = src_family
2855 assert ip.valid_ipv4(src_prefix) or ip.valid_ipv6(src_prefix)
2856 self.src_prefix = src_prefix
2857 self.multi_hop_count = multi_hop_count
2858 self.ifname = ifname
2861 def _parse_family_prefix(cls, buf):
2862 (family,) = struct.unpack_from(cls._FAMILY_FMT, buf)
2863 rest = buf[cls.FAMILY_SIZE:]
2865 if socket.AF_INET == family:
2866 return family, addrconv.ipv4.bin_to_text(rest[:4]), rest[4:]
2867 elif socket.AF_INET6 == family:
2868 return family, addrconv.ipv6.bin_to_text(rest[:16]), rest[16:]
2870 raise struct.error('Unsupported family: %d' % family)
2873 def parse(cls, buf, version=_DEFAULT_VERSION):
2874 (pid,) = struct.unpack_from(cls._HEADER_FMT, buf)
2875 rest = buf[cls.HEADER_SIZE:]
2877 (dst_family, dst_prefix,
2878 rest) = cls._parse_family_prefix(rest)
2880 (min_rx_timer, min_tx_timer, detect_mult,
2881 multi_hop) = struct.unpack_from(cls._BODY_FMT, rest)
2882 rest = rest[cls.BODY_SIZE:]
2884 (src_family, src_prefix,
2885 rest) = cls._parse_family_prefix(rest)
2887 multi_hop_count = None
2890 (multi_hop_count,) = struct.unpack_from(cls._FOOTER_FMT, rest)
2892 (ifname_len,) = struct.unpack_from(cls._FOOTER_FMT, rest)
2893 ifname_bin = rest[cls.FOOTER_SIZE:cls.FOOTER_SIZE + ifname_len]
2894 ifname = str(six.text_type(ifname_bin.strip(b'\x00'), 'ascii'))
2896 return cls(pid, dst_family, dst_prefix,
2897 min_rx_timer, min_tx_timer, detect_mult,
2898 multi_hop, src_family, src_prefix,
2899 multi_hop_count, ifname)
2901 def _serialize_family_prefix(self, prefix):
2902 if ip.valid_ipv4(prefix):
2903 family = socket.AF_INET
2905 struct.pack(self._FAMILY_FMT, family)
2906 + addrconv.ipv4.text_to_bin(prefix))
2907 elif ip.valid_ipv6(prefix):
2908 family = socket.AF_INET6
2910 struct.pack(self._FAMILY_FMT, family)
2911 + addrconv.ipv6.text_to_bin(prefix))
2913 raise ValueError('Invalid prefix: %s' % prefix)
2915 def serialize(self, version=_DEFAULT_VERSION):
2916 (self.dst_family, # fixup
2917 dst_bin) = self._serialize_family_prefix(self.dst_prefix)
2919 body_bin = struct.pack(
2921 self.min_rx_timer, self.min_tx_timer, self.detect_mult,
2924 (self.src_family, # fixup
2925 src_bin) = self._serialize_family_prefix(self.src_prefix)
2928 footer_bin = struct.pack(
2929 self._FOOTER_FMT, self.multi_hop_count)
2931 ifname_bin = self.ifname.encode('ascii')
2932 footer_bin = struct.pack(
2933 self._FOOTER_FMT, len(ifname_bin)) + ifname_bin
2937 self.pid) + dst_bin + body_bin + src_bin + footer_bin
2940 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_REGISTER)
2941 class ZebraBfdDestinationRegister(_ZebraBfdDestination):
2943 Message body class for FRR_ZEBRA_BFD_DEST_REGISTER.
2947 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_DEREGISTER)
2948 class ZebraBfdDestinationDeregister(_ZebraMessageBody):
2950 Message body class for FRR_ZEBRA_BFD_DEST_DEREGISTER.
2953 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2954 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2956 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2958 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2959 # | Destination IPv4/v6 prefix (4 bytes or 16 bytes) |
2960 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2964 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2965 # | Source IPv4/v6 prefix (4 bytes or 16 bytes) |
2966 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2967 # | (MultiHopCnt) | if Multi Hop enabled
2969 # | (IF Name Len) | if Multi Hop disabled
2970 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2971 # | (IF Name (Variable)) if Multi Hop disabled |
2972 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2973 _HEADER_FMT = '!I' # pid
2974 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
2976 FAMILY_SIZE = struct.calcsize(_FAMILY_FMT)
2977 _BODY_FMT = '!B' # multi_hop
2978 BODY_SIZE = struct.calcsize(_BODY_FMT)
2979 _FOOTER_FMT = '!B' # multi_hop_count or ifname_len
2980 FOOTER_SIZE = struct.calcsize(_FOOTER_FMT)
2982 def __init__(self, pid, dst_family, dst_prefix,
2983 multi_hop, src_family, src_prefix,
2984 multi_hop_count=None, ifname=None):
2985 super(ZebraBfdDestinationDeregister, self).__init__()
2987 self.dst_family = dst_family
2988 assert ip.valid_ipv4(dst_prefix) or ip.valid_ipv6(dst_prefix)
2989 self.dst_prefix = dst_prefix
2990 self.multi_hop = multi_hop
2991 self.src_family = src_family
2992 assert ip.valid_ipv4(src_prefix) or ip.valid_ipv6(src_prefix)
2993 self.src_prefix = src_prefix
2994 self.multi_hop_count = multi_hop_count
2995 self.ifname = ifname
2998 def _parse_family_prefix(cls, buf):
2999 (family,) = struct.unpack_from(cls._FAMILY_FMT, buf)
3000 rest = buf[cls.FAMILY_SIZE:]
3002 if socket.AF_INET == family:
3003 return family, addrconv.ipv4.bin_to_text(rest[:4]), rest[4:]
3004 elif socket.AF_INET6 == family:
3005 return family, addrconv.ipv6.bin_to_text(rest[:16]), rest[16:]
3007 raise struct.error('Unsupported family: %d' % family)
3010 def parse(cls, buf, version=_DEFAULT_VERSION):
3011 (pid,) = struct.unpack_from(cls._HEADER_FMT, buf)
3012 rest = buf[cls.HEADER_SIZE:]
3014 (dst_family, dst_prefix,
3015 rest) = cls._parse_family_prefix(rest)
3017 (multi_hop,) = struct.unpack_from(cls._BODY_FMT, rest)
3018 rest = rest[cls.BODY_SIZE:]
3020 (src_family, src_prefix,
3021 rest) = cls._parse_family_prefix(rest)
3023 multi_hop_count = None
3026 (multi_hop_count,) = struct.unpack_from(cls._FOOTER_FMT, rest)
3028 (ifname_len,) = struct.unpack_from(cls._FOOTER_FMT, rest)
3029 ifname_bin = rest[cls.FOOTER_SIZE:cls.FOOTER_SIZE + ifname_len]
3030 ifname = str(six.text_type(ifname_bin.strip(b'\x00'), 'ascii'))
3032 return cls(pid, dst_family, dst_prefix,
3033 multi_hop, src_family, src_prefix,
3034 multi_hop_count, ifname)
3036 def _serialize_family_prefix(self, prefix):
3037 if ip.valid_ipv4(prefix):
3038 family = socket.AF_INET
3040 struct.pack(self._FAMILY_FMT, family)
3041 + addrconv.ipv4.text_to_bin(prefix))
3042 elif ip.valid_ipv6(prefix):
3043 family = socket.AF_INET6
3045 struct.pack(self._FAMILY_FMT, family)
3046 + addrconv.ipv6.text_to_bin(prefix))
3048 raise ValueError('Invalid prefix: %s' % prefix)
3050 def serialize(self, version=_DEFAULT_VERSION):
3051 (self.dst_family, # fixup
3052 dst_bin) = self._serialize_family_prefix(self.dst_prefix)
3054 body_bin = struct.pack(self._BODY_FMT, self.multi_hop)
3056 (self.src_family, # fixup
3057 src_bin) = self._serialize_family_prefix(self.src_prefix)
3060 footer_bin = struct.pack(
3061 self._FOOTER_FMT, self.multi_hop_count)
3063 ifname_bin = self.ifname.encode('ascii')
3064 footer_bin = struct.pack(
3065 self._FOOTER_FMT, len(ifname_bin)) + ifname_bin
3069 self.pid) + dst_bin + body_bin + src_bin + footer_bin
3072 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_UPDATE)
3073 class ZebraBfdDestinationUpdate(_ZebraBfdDestination):
3075 Message body class for FRR_ZEBRA_BFD_DEST_UPDATE.
3079 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_REPLAY)
3080 class ZebraBfdDestinationReply(_ZebraMessageBody):
3082 Message body class for FRR_ZEBRA_BFD_DEST_REPLAY.
3086 class _ZebraRedistributeIPv4(_ZebraIPRoute):
3088 Base class for FRR_ZEBRA_REDISTRIBUTE_IPV4_* message body.
3090 _FAMILY = socket.AF_INET
3093 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV4_ADD)
3094 class ZebraRedistributeIPv4Add(_ZebraRedistributeIPv4):
3096 Message body class for FRR_ZEBRA_IPV4_ROUTE_ADD.
3100 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV4_DEL)
3101 class ZebraRedistributeIPv4Delete(_ZebraRedistributeIPv4):
3103 Message body class for FRR_ZEBRA_IPV4_ROUTE_DELETE.
3107 class _ZebraRedistributeIPv6(_ZebraIPRoute):
3109 Base class for FRR_ZEBRA_REDISTRIBUTE_IPV6_* message body.
3111 _FAMILY = socket.AF_INET6
3114 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV6_ADD)
3115 class ZebraRedistributeIPv6Add(_ZebraRedistributeIPv6):
3117 Message body class for FRR_ZEBRA_REDISTRIBUTE_IPV6_ADD.
3121 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV6_DEL)
3122 class ZebraRedistributeIPv6Delete(_ZebraRedistributeIPv6):
3124 Message body class for FRR_ZEBRA_REDISTRIBUTE_IPV6_DEL.
3128 class _ZebraVrf(_ZebraMessageBody):
3130 Base class for FRR_ZEBRA_VRF_ADD and FRR_ZEBRA_VRF_DELETE message body.
3132 # Zebra VRF Add/Delete message body:
3134 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
3135 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3136 # | VRF Name (VRF_NAMSIZ bytes length) |
3137 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3138 _HEADER_FMT = '!%ds' % VRF_NAMSIZ
3140 def __init__(self, vrf_name):
3141 super(_ZebraVrf, self).__init__()
3142 self.vrf_name = vrf_name
3145 def parse(cls, buf, version=_DEFAULT_FRR_VERSION):
3146 vrf_name_bin = buf[:VRF_NAMSIZ]
3147 vrf_name = str(six.text_type(vrf_name_bin.strip(b'\x00'), 'ascii'))
3149 return cls(vrf_name)
3151 def serialize(self, version=_DEFAULT_FRR_VERSION):
3152 return struct.pack(self._HEADER_FMT, self.vrf_name.encode('ascii'))
3155 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_VRF_ADD)
3156 class ZebraVrfAdd(_ZebraVrf):
3158 Message body class for FRR_ZEBRA_VRF_ADD.
3162 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_VRF_DELETE)
3163 class ZebraVrfDelete(_ZebraVrf):
3165 Message body class for FRR_ZEBRA_VRF_DELETE.
3169 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_VRF_UPDATE)
3170 class ZebraInterfaceVrfUpdate(_ZebraMessageBody):
3172 Message body class for FRR_ZEBRA_INTERFACE_VRF_UPDATE.
3174 # Zebra Interface VRF Update message body:
3176 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
3177 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3178 # | Interface Index |
3179 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3181 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3182 _HEADER_FMT = '!IH' # ifindex, vrf_id
3184 def __init__(self, ifindex, vrf_id):
3185 super(ZebraInterfaceVrfUpdate, self).__init__()
3186 self.ifindex = ifindex
3187 self.vrf_id = vrf_id
3190 def parse(cls, buf, version=_DEFAULT_FRR_VERSION):
3191 (ifindex, vrf_id) = struct.unpack_from(cls._HEADER_FMT, buf)
3193 return cls(ifindex, vrf_id)
3195 def serialize(self, version=_DEFAULT_FRR_VERSION):
3196 return struct.pack(self._HEADER_FMT, self.ifindex, self.vrf_id)
3199 class _ZebraBfdClient(_ZebraMessageBody):
3201 Base class for FRR_ZEBRA_BFD_CLIENT_*.
3203 # Zebra BFD Client message body:
3205 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
3206 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3208 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3209 _HEADER_FMT = '!I' # pid
3210 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
3212 def __init__(self, pid):
3213 super(_ZebraBfdClient, self).__init__()
3217 def parse(cls, buf, version=_DEFAULT_FRR_VERSION):
3218 (pid,) = struct.unpack_from(cls._HEADER_FMT, buf)
3222 def serialize(self, version=_DEFAULT_FRR_VERSION):
3223 return struct.pack(self._HEADER_FMT, self.pid)
3226 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_CLIENT_REGISTER)
3227 class ZebraBfdClientRegister(_ZebraBfdClient):
3229 Message body class for FRR_ZEBRA_BFD_CLIENT_REGISTER.
3233 class _ZebraInterfaceRadv(_ZebraMessageBody):
3235 Base class for FRR_ZEBRA_INTERFACE_*_RADV message body.
3237 # Zebra interface Router Advertisement message body:
3239 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
3240 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3241 # | Interface Index |
3242 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3244 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3245 _HEADER_FMT = '!II' # ifindex, interval
3246 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
3248 def __init__(self, ifindex, interval):
3249 super(_ZebraInterfaceRadv, self).__init__()
3250 self.ifindex = ifindex
3251 self.interval = interval
3254 def parse(cls, buf, version=_DEFAULT_FRR_VERSION):
3255 (ifindex, interval,) = struct.unpack_from(cls._HEADER_FMT, buf)
3257 return cls(ifindex, interval)
3259 def serialize(self, version=_DEFAULT_FRR_VERSION):
3260 return struct.pack(self._HEADER_FMT, self.ifindex, self.interval)
3263 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ENABLE_RADV)
3264 class ZebraInterfaceEnableRadv(_ZebraInterfaceRadv):
3266 Message body class for FRR_ZEBRA_INTERFACE_ENABLE_RADV.
3270 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_DISABLE_RADV)
3271 class ZebraInterfaceDisableRadv(_ZebraInterfaceRadv):
3273 Message body class for FRR_ZEBRA_INTERFACE_DISABLE_RADV.
3277 class _ZebraMplsLabels(_ZebraMessageBody):
3279 Base class for ZEBRA_MPLS_LABELS_* message body.
3281 # Zebra MPLS Labels message body:
3283 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
3284 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3286 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3288 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3289 # | IPv4/v6 Prefix (4 bytes/16 bytes) |
3290 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3292 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3293 # | Gate IPv4/v6 Address (4 bytes/16 bytes) |
3294 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3295 # | Interface Index: v4(FRRouting v3.0 or later) |
3296 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3298 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3300 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3302 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3303 _HEADER_FMT = '!B' # route_type
3304 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
3306 FAMILY_SIZE = struct.calcsize(_FAMILY_FMT)
3307 _IPV4_PREFIX_FMT = '!4sB' # prefix, prefix_len
3308 _IPV6_PREFIX_FMT = '!16sB'
3309 IPV4_PREFIX_SIZE = struct.calcsize(_IPV4_PREFIX_FMT)
3310 IPV6_PREFIX_SIZE = struct.calcsize(_IPV6_PREFIX_FMT)
3311 _FAMILY_IPV4_PREFIX_FMT = '!I4sB'
3312 _FAMILY_IPV6_PREFIX_FMT = '!I16sB'
3314 IFINDEX_SIZE = struct.calcsize(_IFINDEX_FMT)
3315 _BODY_FMT = '!BII' # distance, in_label, out_label
3317 def __init__(self, route_type, family, prefix, gate_addr, ifindex=None,
3318 distance=None, in_label=None, out_label=None):
3319 super(_ZebraMplsLabels, self).__init__()
3320 self.route_type = route_type
3321 self.family = family
3322 if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
3323 prefix = prefix.prefix
3324 self.prefix = prefix
3325 assert ip.valid_ipv4(gate_addr) or ip.valid_ipv6(gate_addr)
3326 self.gate_addr = gate_addr
3327 if _is_frr_version_ge(_FRR_VERSION_3_0):
3328 assert ifindex is not None
3329 self.ifindex = ifindex
3330 assert distance is not None
3331 self.distance = distance
3332 assert in_label is not None
3333 self.in_label = in_label
3334 assert out_label is not None
3335 self.out_label = out_label
3338 def _parse_family_prefix(cls, buf):
3339 (family,) = struct.unpack_from(cls._FAMILY_FMT, buf)
3340 rest = buf[cls.FAMILY_SIZE:]
3342 if socket.AF_INET == family:
3343 (prefix, p_len) = struct.unpack_from(cls._IPV4_PREFIX_FMT, rest)
3344 prefix = '%s/%d' % (addrconv.ipv4.bin_to_text(prefix), p_len)
3345 rest = rest[cls.IPV4_PREFIX_SIZE:]
3346 elif socket.AF_INET6 == family:
3347 (prefix, p_len) = struct.unpack_from(cls._IPV6_PREFIX_FMT, rest)
3348 prefix = '%s/%d' % (addrconv.ipv6.bin_to_text(prefix), p_len)
3349 rest = rest[cls.IPV6_PREFIX_SIZE:]
3351 raise struct.error('Unsupported family: %d' % family)
3353 return family, prefix, rest
3356 def parse(cls, buf, version=_DEFAULT_FRR_VERSION):
3357 (route_type,) = struct.unpack_from(cls._HEADER_FMT, buf)
3358 rest = buf[cls.HEADER_SIZE:]
3360 (family, prefix, rest) = cls._parse_family_prefix(rest)
3362 if family == socket.AF_INET:
3363 gate_addr = addrconv.ipv4.bin_to_text(rest[:4])
3365 elif family == socket.AF_INET6:
3366 gate_addr = addrconv.ipv6.bin_to_text(rest[:16])
3369 raise struct.error('Unsupported family: %d' % family)
3372 if _is_frr_version_ge(_FRR_VERSION_3_0):
3373 (ifindex,) = struct.unpack_from(cls._IFINDEX_FMT, rest)
3374 rest = rest[cls.IFINDEX_SIZE:]
3376 (distance, in_label,
3377 out_label) = struct.unpack_from(cls._BODY_FMT, rest)
3379 return cls(route_type, family, prefix, gate_addr, ifindex,
3380 distance, in_label, out_label)
3382 def _serialize_family_prefix(self, prefix):
3383 if ip.valid_ipv4(prefix):
3384 family = socket.AF_INET # fixup
3385 prefix_addr, prefix_num = prefix.split('/')
3386 return family, struct.pack(
3387 self._FAMILY_IPV4_PREFIX_FMT,
3389 addrconv.ipv4.text_to_bin(prefix_addr),
3391 elif ip.valid_ipv6(prefix):
3392 family = socket.AF_INET6 # fixup
3393 prefix_addr, prefix_num = prefix.split('/')
3394 return family, struct.pack(
3395 self._FAMILY_IPV6_PREFIX_FMT,
3397 addrconv.ipv6.text_to_bin(prefix_addr),
3400 raise ValueError('Invalid prefix: %s' % prefix)
3402 def serialize(self, version=_DEFAULT_FRR_VERSION):
3403 (self.family, # fixup
3404 prefix_bin) = self._serialize_family_prefix(self.prefix)
3406 if self.family == socket.AF_INET:
3407 gate_addr_bin = addrconv.ipv4.text_to_bin(self.gate_addr)
3408 elif self.family == socket.AF_INET6:
3409 gate_addr_bin = addrconv.ipv6.text_to_bin(self.gate_addr)
3411 raise ValueError('Unsupported family: %d' % self.family)
3414 if _is_frr_version_ge(_FRR_VERSION_3_0):
3415 body_bin = struct.pack(self._IFINDEX_FMT, self.ifindex)
3417 body_bin += struct.pack(
3418 self._BODY_FMT, self.distance, self.in_label, self.out_label)
3422 self.route_type) + prefix_bin + gate_addr_bin + body_bin
3425 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_MPLS_LABELS_ADD)
3426 class ZebraMplsLabelsAdd(_ZebraMplsLabels):
3428 Message body class for FRR_ZEBRA_MPLS_LABELS_ADD.
3432 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_MPLS_LABELS_DELETE)
3433 class ZebraMplsLabelsDelete(_ZebraMplsLabels):
3435 Message body class for FRR_ZEBRA_MPLS_LABELS_DELETE.
3439 class _ZebraIPv4Nexthop(_ZebraIPRoute):
3441 Base class for FRR_ZEBRA_IPV4_NEXTHOP_* message body.
3443 _FAMILY = socket.AF_INET
3446 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_NEXTHOP_ADD)
3447 class ZebraIPv4NexthopAdd(_ZebraIPv4Nexthop):
3449 Message body class for FRR_ZEBRA_IPV4_NEXTHOP_ADD.
3453 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_NEXTHOP_DELETE)
3454 class ZebraIPv4NexthopDelete(_ZebraIPv4Nexthop):
3456 Message body class for FRR_ZEBRA_IPV4_NEXTHOP_DELETE.
3460 class _ZebraIPv6Nexthop(_ZebraIPRoute):
3462 Base class for FRR_ZEBRA_IPV6_NEXTHOP_* message body.
3464 _FAMILY = socket.AF_INET6
3467 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_NEXTHOP_ADD)
3468 class ZebraIPv6NexthopAdd(_ZebraIPv6Nexthop):
3470 Message body class for FRR_ZEBRA_IPV6_NEXTHOP_ADD.
3474 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_NEXTHOP_DELETE)
3475 class ZebraIPv6NexthopDelete(_ZebraIPv6Nexthop):
3477 Message body class for FRR_ZEBRA_IPV6_NEXTHOP_DELETE.