backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / packet / zebra.py
1 # Copyright (C) 2017 Nippon Telegraph and Telephone Corporation.
2 #
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
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
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
12 # implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 """
17 Zebra protocol parser/serializer
18
19 Zebra Protocol is used to communicate with the zebra daemon.
20 """
21
22 import abc
23 import socket
24 import struct
25 import logging
26 from distutils.version import LooseVersion
27
28 import netaddr
29 import six
30
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
38 from . import bgp
39 from . import safi as packet_safi
40
41
42 LOG = logging.getLogger(__name__)
43
44 # Default Zebra protocol version
45 _DEFAULT_VERSION = 3
46 _DEFAULT_FRR_VERSION = 4
47
48 _FRR_VERSION_2_0 = LooseVersion('2.0')
49 _FRR_VERSION_3_0 = LooseVersion('3.0')
50
51 # Constants in quagga/lib/zebra.h
52
53 # Default Zebra TCP port
54 ZEBRA_PORT = 2600
55
56 # Zebra message types
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
79 ZEBRA_HELLO = 23
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
87
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
106 FRR_ZEBRA_HELLO = 17
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
140
141 # Zebra route types
142 ZEBRA_ROUTE_SYSTEM = 0
143 ZEBRA_ROUTE_KERNEL = 1
144 ZEBRA_ROUTE_CONNECT = 2
145 ZEBRA_ROUTE_STATIC = 3
146 ZEBRA_ROUTE_RIP = 4
147 ZEBRA_ROUTE_RIPNG = 5
148 ZEBRA_ROUTE_OSPF = 6
149 ZEBRA_ROUTE_OSPF6 = 7
150 ZEBRA_ROUTE_ISIS = 8
151 ZEBRA_ROUTE_BGP = 9
152 ZEBRA_ROUTE_PIM = 10
153 ZEBRA_ROUTE_HSLS = 11
154 ZEBRA_ROUTE_OLSR = 12
155 ZEBRA_ROUTE_BABEL = 13
156 ZEBRA_ROUTE_MAX = 14
157
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
181
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
191
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
202
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
213
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
221
222 # Constants in quagga/lib/zclient.h
223
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
231
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
242
243 # Constants in quagga/lib/if.h
244
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
252
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
259
260 # Zebra interface connected address flags
261 ZEBRA_IFA_SECONDARY = 1 << 0
262 ZEBRA_IFA_PEER = 1 << 1
263 ZEBRA_IFA_UNNUMBERED = 1 << 2
264
265 # Zebra link layer types
266 ZEBRA_LLT_UNKNOWN = 0
267 ZEBRA_LLT_ETHER = 1
268 ZEBRA_LLT_EETHER = 2
269 ZEBRA_LLT_AX25 = 3
270 ZEBRA_LLT_PRONET = 4
271 ZEBRA_LLT_IEEE802 = 5
272 ZEBRA_LLT_ARCNET = 6
273 ZEBRA_LLT_APPLETLK = 7
274 ZEBRA_LLT_DLCI = 8
275 ZEBRA_LLT_ATM = 9
276 ZEBRA_LLT_METRICOM = 10
277 ZEBRA_LLT_IEEE1394 = 11
278 ZEBRA_LLT_EUI64 = 12
279 ZEBRA_LLT_INFINIBAND = 13
280 ZEBRA_LLT_SLIP = 14
281 ZEBRA_LLT_CSLIP = 15
282 ZEBRA_LLT_SLIP6 = 16
283 ZEBRA_LLT_CSLIP6 = 17
284 ZEBRA_LLT_RSRVD = 18
285 ZEBRA_LLT_ADAPT = 19
286 ZEBRA_LLT_ROSE = 20
287 ZEBRA_LLT_X25 = 21
288 ZEBRA_LLT_PPP = 22
289 ZEBRA_LLT_CHDLC = 23
290 ZEBRA_LLT_LAPB = 24
291 ZEBRA_LLT_RAWHDLC = 25
292 ZEBRA_LLT_IPIP = 26
293 ZEBRA_LLT_IPIP6 = 27
294 ZEBRA_LLT_FRAD = 28
295 ZEBRA_LLT_SKIP = 29
296 ZEBRA_LLT_LOOPBACK = 30
297 ZEBRA_LLT_LOCALTLK = 31
298 ZEBRA_LLT_FDDI = 32
299 ZEBRA_LLT_SIT = 33
300 ZEBRA_LLT_IPDDP = 34
301 ZEBRA_LLT_IPGRE = 35
302 ZEBRA_LLT_IP6GRE = 36
303 ZEBRA_LLT_PIMREG = 37
304 ZEBRA_LLT_HIPPI = 38
305 ZEBRA_LLT_ECONET = 39
306 ZEBRA_LLT_IRDA = 40
307 ZEBRA_LLT_FCPP = 41
308 ZEBRA_LLT_FCAL = 42
309 ZEBRA_LLT_FCPL = 43
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
316
317 # Link Parameters Status
318 LP_UNSET = 0x0000
319 LP_TE = 0x0001
320 LP_MAX_BW = 0x0002
321 LP_MAX_RSV_BW = 0x0004
322 LP_UNRSV_BW = 0x0008
323 LP_ADM_GRP = 0x0010
324 LP_RMT_AS = 0x0020
325 LP_DELAY = 0x0040
326 LP_MM_DELAY = 0x0080
327 LP_DELAY_VAR = 0x0100
328 LP_PKT_LOSS = 0x0200
329 LP_RES_BW = 0x0400
330 LP_AVA_BW = 0x0800
331 LP_USE_BW = 0x1000
332 LP_TE_METRIC = 0x2000
333
334 # "non-official" architectural constants
335 MAX_CLASS_TYPE = 8
336
337 # Constants in frr/zebra/zebra_ptm.h
338
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
343
344 # PTM status
345 ZEBRA_PTM_STATUS_DOWN = 0
346 ZEBRA_PTM_STATUS_UP = 1
347 ZEBRA_PTM_STATUS_UNKNOWN = 2
348
349 # Constants in frr/lib/bfd.h
350
351 # BFD status
352 BFD_STATUS_UNKNOWN = 1 << 0
353 BFD_STATUS_DOWN = 1 << 1
354 BFD_STATUS_UP = 1 << 2
355
356 # Constants in frr/lib/vrf.h
357
358 # VRF name length
359 VRF_NAMSIZ = 36
360
361 # Constants in frr/lib/mpls.h
362
363 # Reserved MPLS label values
364 MPLS_V4_EXP_NULL_LABEL = 0
365 MPLS_RA_LABEL = 1
366 MPLS_V6_EXP_NULL_LABEL = 2
367 MPLS_IMP_NULL_LABEL = 3
368 MPLS_ENTROPY_LABEL_INDICATOR = 7
369 MPLS_GAL_LABEL = 13
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
376
377
378 # Utility functions/classes
379
380 IPv4Prefix = bgp.IPAddrPrefix
381 IPv6Prefix = bgp.IP6AddrPrefix
382
383
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)
389     else:
390         raise struct.error('Unsupported family: %d' % family)
391
392     return prefix.prefix, rest
393
394
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()
402     else:
403         raise ValueError('Invalid prefix: %s' % prefix)
404
405
406 # Family and Zebra Prefix format:
407 #  0                   1                   2                   3
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 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
410 # | Family        |
411 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
412 # | IPv4/v6 prefix (4 bytes or 16 bytes)                          |
413 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
414 # | Prefix len    |
415 # +-+-+-+-+-+-+-+-+
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
424
425
426 def _parse_zebra_family_prefix(buf):
427     """
428     Parses family and prefix in Zebra format.
429     """
430     (family,) = struct.unpack_from(_ZEBRA_FAMILY_FMT, buf)
431     rest = buf[_ZEBRA_FAMILY_SIZE:]
432
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:]
441     else:
442         raise struct.error('Unsupported family: %d' % family)
443
444     return family, prefix, rest
445
446
447 def _serialize_zebra_family_prefix(prefix):
448     """
449     Serializes family and prefix in Zebra format.
450     """
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,
456             family,
457             addrconv.ipv4.text_to_bin(prefix_addr),
458             int(prefix_num))
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,
464             family,
465             addrconv.ipv6.text_to_bin(prefix_addr),
466             int(prefix_num))
467
468     raise ValueError('Invalid prefix: %s' % prefix)
469
470
471 def _is_frr_version_ge(compared_version):
472     return CONF['zapi'].frr_version >= compared_version
473
474
475 class InterfaceLinkParams(stringify.StringifyMixin):
476     """
477     Interface Link Parameters class for if_link_params structure.
478     """
479     # Interface Link Parameters structure:
480     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
504     # | Link Min Delay                                                |
505     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
506     # | Link Max Delay                                                |
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)
521     _REPEATED_FMT = '!f'
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)
528
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
536         self.max_bw = max_bw
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
553
554     @classmethod
555     def parse(cls, buf):
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
561
562         unreserved_bw = []
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
567
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
573
574         remote_ip = addrconv.ipv4.bin_to_text(remote_ip)
575
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:]
580
581     def serialize(self):
582         buf = struct.pack(
583             self._HEADER_FMT, self.lp_status, self.te_metric, self.max_bw,
584             self.max_reserved_bw, len(self.unreserved_bw))
585
586         for u_bw in self.unreserved_bw:
587             buf += struct.pack(self._REPEATED_FMT, u_bw)
588
589         remote_ip = addrconv.ipv4.text_to_bin(self.remote_ip)
590
591         buf += struct.pack(
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,
595             self.utilized_bw)
596
597         return buf
598
599
600 @six.add_metaclass(abc.ABCMeta)
601 class _NextHop(type_desc.TypeDisp, stringify.StringifyMixin):
602     """
603     Base class for Zebra Nexthop structure.
604     """
605     # Zebra Nexthop structure:
606     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
609     # | Nexthop Type  |
610     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
611     # | IPv4/v6 address or Interface Index number (Variable)          |
612     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
613     _HEADER_FMT = '!B'
614     HEADER_SIZE = struct.calcsize(_HEADER_FMT)
615
616     def __init__(self, ifindex=None, ifname=None, addr=None, type_=None):
617         super(_NextHop, self).__init__()
618         self.ifindex = ifindex
619         self.ifname = ifname
620         self.addr = addr
621         self.type = type_
622
623     @classmethod
624     @abc.abstractmethod
625     def parse(cls, buf):
626         (type_,) = struct.unpack_from(cls._HEADER_FMT, buf)
627         rest = buf[cls.HEADER_SIZE:]
628
629         subcls = cls._lookup_type(type_)
630         if subcls is None:
631             raise struct.error('unsupported Nexthop type: %d' % type_)
632
633         nexthop, rest = subcls.parse(rest)
634         nexthop.type = type_
635         return nexthop, rest
636
637     @abc.abstractmethod
638     def _serialize(self):
639         return b''
640
641     def serialize(self, version=_DEFAULT_VERSION):
642         if self.type is None:
643             if version <= 3:
644                 nh_cls = _NextHop
645             elif version == 4:
646                 nh_cls = _FrrNextHop
647             else:
648                 raise ValueError(
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()
652
653
654 @six.add_metaclass(abc.ABCMeta)
655 class _FrrNextHop(_NextHop):
656     """
657     Base class for Zebra Nexthop structure for translating nexthop types
658     on FRRouting.
659     """
660
661
662 _NEXTHOP_COUNT_FMT = '!B'  # nexthop_count
663 _NEXTHOP_COUNT_SIZE = struct.calcsize(_NEXTHOP_COUNT_FMT)
664
665
666 def _parse_nexthops(buf, version=_DEFAULT_VERSION):
667     (nexthop_count,) = struct.unpack_from(_NEXTHOP_COUNT_FMT, buf)
668     rest = buf[_NEXTHOP_COUNT_SIZE:]
669
670     if version <= 3:
671         nh_cls = _NextHop
672     elif version == 4:
673         nh_cls = _FrrNextHop
674     else:
675         raise struct.error(
676             'Unsupported Zebra protocol version: %d' % version)
677
678     nexthops = []
679     for _ in range(nexthop_count):
680         nexthop, rest = nh_cls.parse(rest)
681         nexthops.append(nexthop)
682
683     return nexthops, rest
684
685
686 def _serialize_nexthops(nexthops, version=_DEFAULT_VERSION):
687     nexthop_count = len(nexthops)
688     buf = struct.pack(_NEXTHOP_COUNT_FMT, nexthop_count)
689
690     if nexthop_count == 0:
691         return buf
692
693     for nexthop in nexthops:
694         buf += nexthop.serialize(version=version)
695
696     return buf
697
698
699 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IFINDEX)
700 @_NextHop.register_type(ZEBRA_NEXTHOP_IFINDEX)
701 class NextHopIFIndex(_NextHop):
702     """
703     Nexthop class for ZEBRA_NEXTHOP_IFINDEX type.
704     """
705     _BODY_FMT = '!I'  # ifindex
706     BODY_SIZE = struct.calcsize(_BODY_FMT)
707
708     @classmethod
709     def parse(cls, buf):
710         (ifindex,) = struct.unpack_from(cls._BODY_FMT, buf)
711         rest = buf[cls.BODY_SIZE:]
712
713         return cls(ifindex=ifindex), rest
714
715     def _serialize(self):
716         return struct.pack(self._BODY_FMT, self.ifindex)
717
718
719 @_NextHop.register_type(ZEBRA_NEXTHOP_IFNAME)
720 class NextHopIFName(_NextHop):
721     """
722     Nexthop class for ZEBRA_NEXTHOP_IFNAME type.
723     """
724     _BODY_FMT = '!I'  # ifindex
725     BODY_SIZE = struct.calcsize(_BODY_FMT)
726
727     @classmethod
728     def parse(cls, buf):
729         (ifindex,) = struct.unpack_from(cls._BODY_FMT, buf)
730         rest = buf[cls.BODY_SIZE:]
731
732         return cls(ifindex=ifindex), rest
733
734     def _serialize(self):
735         return struct.pack(self._BODY_FMT, self.ifindex)
736
737
738 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV4)
739 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV4)
740 class NextHopIPv4(_NextHop):
741     """
742     Nexthop class for ZEBRA_NEXTHOP_IPV4 type.
743     """
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)
748
749     @classmethod
750     def parse(cls, buf):
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
756
757         addr = addrconv.ipv4.bin_to_text(buf[:cls.BODY_SIZE])
758         rest = buf[cls.BODY_SIZE:]
759
760         return cls(addr=addr), rest
761
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)
766
767         return addrconv.ipv4.text_to_bin(self.addr)
768
769
770 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV4_IFINDEX)
771 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV4_IFINDEX)
772 class NextHopIPv4IFIndex(_NextHop):
773     """
774     Nexthop class for ZEBRA_NEXTHOP_IPV4_IFINDEX type.
775     """
776     _BODY_FMT = '!4sI'  # addr(IPv4), ifindex
777     BODY_SIZE = struct.calcsize(_BODY_FMT)
778
779     @classmethod
780     def parse(cls, buf):
781         (addr, ifindex) = struct.unpack_from(cls._BODY_FMT, buf)
782         addr = addrconv.ipv4.bin_to_text(addr)
783         rest = buf[cls.BODY_SIZE:]
784
785         return cls(ifindex=ifindex, addr=addr), rest
786
787     def _serialize(self):
788         addr = addrconv.ipv4.text_to_bin(self.addr)
789
790         return struct.pack(self._BODY_FMT, addr, self.ifindex)
791
792
793 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV4_IFNAME)
794 class NextHopIPv4IFName(_NextHop):
795     """
796     Nexthop class for ZEBRA_NEXTHOP_IPV4_IFNAME type.
797     """
798     _BODY_FMT = '!4sI'  # addr(IPv4), ifindex
799     BODY_SIZE = struct.calcsize(_BODY_FMT)
800
801     @classmethod
802     def parse(cls, buf):
803         (addr, ifindex) = struct.unpack_from(cls._BODY_FMT, buf)
804         addr = addrconv.ipv4.bin_to_text(addr)
805         rest = buf[cls.BODY_SIZE:]
806
807         return cls(ifindex=ifindex, addr=addr), rest
808
809     def _serialize(self):
810         addr = addrconv.ipv4.text_to_bin(self.addr)
811
812         return struct.pack(self._BODY_FMT, addr, self.ifindex)
813
814
815 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV6)
816 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV6)
817 class NextHopIPv6(_NextHop):
818     """
819     Nexthop class for ZEBRA_NEXTHOP_IPV6 type.
820     """
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)
825
826     @classmethod
827     def parse(cls, buf):
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
833
834         addr = addrconv.ipv6.bin_to_text(buf[:cls.BODY_SIZE])
835         rest = buf[cls.BODY_SIZE:]
836
837         return cls(addr=addr), rest
838
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)
843
844         return addrconv.ipv6.text_to_bin(self.addr)
845
846
847 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_IPV6_IFINDEX)
848 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV6_IFINDEX)
849 class NextHopIPv6IFIndex(_NextHop):
850     """
851     Nexthop class for ZEBRA_NEXTHOP_IPV6_IFINDEX type.
852     """
853     _BODY_FMT = '!16sI'  # addr(IPv6), ifindex
854     BODY_SIZE = struct.calcsize(_BODY_FMT)
855
856     @classmethod
857     def parse(cls, buf):
858         (addr, ifindex) = struct.unpack_from(cls._BODY_FMT, buf)
859         addr = addrconv.ipv6.bin_to_text(addr)
860         rest = buf[cls.BODY_SIZE:]
861
862         return cls(ifindex=ifindex, addr=addr), rest
863
864     def _serialize(self):
865         addr = addrconv.ipv6.text_to_bin(self.addr)
866
867         return struct.pack(self._BODY_FMT, addr, self.ifindex)
868
869
870 @_NextHop.register_type(ZEBRA_NEXTHOP_IPV6_IFNAME)
871 class NextHopIPv6IFName(_NextHop):
872     """
873     Nexthop class for ZEBRA_NEXTHOP_IPV6_IFNAME type.
874     """
875     _BODY_FMT = '!16sI'  # addr(IPv6), ifindex
876     BODY_SIZE = struct.calcsize(_BODY_FMT)
877
878     @classmethod
879     def parse(cls, buf):
880         (addr, ifindex) = struct.unpack_from(cls._BODY_FMT, buf)
881         addr = addrconv.ipv6.bin_to_text(addr)
882         rest = buf[cls.BODY_SIZE:]
883
884         return cls(ifindex=ifindex, addr=addr), rest
885
886     def _serialize(self):
887         addr = addrconv.ipv6.text_to_bin(self.addr)
888
889         return struct.pack(self._BODY_FMT, addr, self.ifindex)
890
891
892 @_FrrNextHop.register_type(FRR_ZEBRA_NEXTHOP_BLACKHOLE)
893 @_NextHop.register_type(ZEBRA_NEXTHOP_BLACKHOLE)
894 class NextHopBlackhole(_NextHop):
895     """
896     Nexthop class for ZEBRA_NEXTHOP_BLACKHOLE type.
897     """
898
899     @classmethod
900     def parse(cls, buf):
901         return cls(), buf
902
903     def _serialize(self):
904         return b''
905
906
907 class RegisteredNexthop(stringify.StringifyMixin):
908     """
909     Unit of ZEBRA_NEXTHOP_REGISTER message body.
910     """
911     # Unit of Zebra Nexthop Register message body:
912     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
919     _HEADER_FMT = '!?H'
920     HEADER_SIZE = struct.calcsize(_HEADER_FMT)
921     # Note: connected is renamed to flags on FRRouting.
922
923     def __init__(self, connected, family, prefix):
924         super(RegisteredNexthop, self).__init__()
925         self.connected = connected
926         self.family = family
927         if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
928             prefix = prefix.prefix
929         self.prefix = prefix
930
931     @property
932     def flags(self):
933         return self.connected
934
935     @flags.setter
936     def flags(self, v):
937         self.connected = v
938
939     @classmethod
940     def parse(cls, buf):
941         (connected, family) = struct.unpack_from(cls._HEADER_FMT, buf)
942         rest = buf[cls.HEADER_SIZE:]
943
944         prefix, rest = _parse_ip_prefix(family, rest)
945
946         return cls(connected, family, prefix), rest
947
948     def serialize(self):
949         buf = struct.pack(self._HEADER_FMT, self.connected, self.family)
950
951         return buf + _serialize_ip_prefix(self.prefix)
952
953
954 # Zebra message class
955
956 class ZebraMessage(packet_base.PacketBase):
957     """
958     Zebra protocol parser/serializer class.
959
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.
963
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
970                    3 messages.
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.
978     body           Messages body.
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     ============== ==========================================================
983
984     .. Note::
985
986         To instantiate Zebra messages, ``command`` can be omitted when the
987         valid ``body`` is specified.
988
989         ::
990
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)
995
996         On the other hand, if ``body`` is omitted, ``command`` must be
997         specified.
998
999         ::
1000
1001             >>> zebra.ZebraMessage(command=zebra.ZEBRA_INTERFACE_ADD)
1002             ZebraMessage(body=None,command=1,length=None,version=3,vrf_id=0)
1003     """
1004
1005     # Zebra Protocol Common Header (version 0):
1006     #  0                   1                   2                   3
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
1014
1015     # Zebra Protocol Common Header (version 1):
1016     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1021     # | Command                       |
1022     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1023     _V1_HEADER_FMT = '!HBBH'
1024     V1_HEADER_SIZE = struct.calcsize(_V1_HEADER_FMT)
1025
1026     # Zebra Protocol Common Header (version 3):
1027     #  0                   1                   2                   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)
1036
1037     # Note: Marker should be 0xff(=255) in the version>=1 header.
1038     # Also, FRRouting uses the different marker value.
1039     _MARKER = 0xff
1040     _LT_MARKER = 0xfe
1041
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
1049         self.body = body
1050
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__)
1057
1058     @classmethod
1059     def get_header_size(cls, version):
1060         if version == 0:
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
1066         else:
1067             raise ValueError(
1068                 'Unsupported Zebra protocol version: %d'
1069                 % version)
1070
1071     @classmethod
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]:
1075             command = marker
1076             body_buf = buf[cls.V0_HEADER_SIZE:length]
1077             # version=0, vrf_id=0
1078             return length, 0, 0, command, body_buf
1079
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]
1084             # vrf_id=0
1085             return length, version, 0, command, body_buf
1086
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
1092
1093         raise struct.error(
1094             'Failed to parse Zebra protocol header: '
1095             'marker=%d, version=%d' % (marker, version))
1096
1097     @classmethod
1098     def get_body_class(cls, version, command):
1099         if version == 4:
1100             return _FrrZebraMessageBody.lookup_command(command)
1101         else:
1102             return _ZebraMessageBody.lookup_command(command)
1103
1104     @classmethod
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)
1109
1110         if body_buf:
1111             body_cls = cls.get_body_class(version, command)
1112             if from_zebra:
1113                 body = body_cls.parse_from_zebra(body_buf, version=version)
1114             else:
1115                 body = body_cls.parse(body_buf, version=version)
1116         else:
1117             body = None
1118
1119         rest = buf[length:]
1120
1121         if from_zebra:
1122             return (cls(length, version, vrf_id, command, body),
1123                     _ZebraMessageFromZebra, rest)
1124
1125         return cls(length, version, vrf_id, command, body), cls, rest
1126
1127     @classmethod
1128     def parser(cls, buf):
1129         return cls._parser_impl(buf)
1130
1131     def serialize_header(self, body_len):
1132         if self.version == 0:
1133             self.length = self.V0_HEADER_SIZE + body_len  # fixup
1134             return struct.pack(
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
1139             return struct.pack(
1140                 self._V1_HEADER_FMT,
1141                 self.length, self._MARKER, self.version,
1142                 self.command)
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
1149             return struct.pack(
1150                 self._V3_HEADER_FMT,
1151                 self.length, _marker, self.version,
1152                 self.vrf_id, self.command)
1153         else:
1154             raise ValueError(
1155                 'Unsupported Zebra protocol version: %d'
1156                 % self.version)
1157
1158     def serialize(self, _payload=None, _prev=None):
1159         if self.body is None:
1160             assert self.command is not None
1161             body = b''
1162         else:
1163             assert isinstance(self.body, _ZebraMessageBody)
1164             self._fill_command()  # fixup
1165             body = self.body.serialize(version=self.version)
1166
1167         return self.serialize_header(len(body)) + body
1168
1169
1170 class _ZebraMessageFromZebra(ZebraMessage):
1171     """
1172     This class is corresponding to the message sent from Zebra daemon.
1173     """
1174
1175     @classmethod
1176     def parser(cls, buf):
1177         return ZebraMessage._parser_impl(buf, from_zebra=True)
1178
1179
1180 # Alias
1181 zebra = ZebraMessage
1182
1183
1184 # Zebra message body classes
1185
1186 class _ZebraMessageBody(type_desc.TypeDisp, stringify.StringifyMixin):
1187     """
1188     Base class for Zebra message body.
1189     """
1190
1191     @classmethod
1192     def lookup_command(cls, command):
1193         return cls._lookup_type(command)
1194
1195     @classmethod
1196     def rev_lookup_command(cls, body_cls):
1197         return cls._rev_lookup_type(body_cls)
1198
1199     @classmethod
1200     def parse(cls, buf, version=_DEFAULT_VERSION):
1201         return cls()
1202
1203     @classmethod
1204     def parse_from_zebra(cls, buf, version=_DEFAULT_VERSION):
1205         return cls.parse(buf, version=version)
1206
1207     def serialize(self, version=_DEFAULT_VERSION):
1208         return b''
1209
1210
1211 class _FrrZebraMessageBody(_ZebraMessageBody):
1212     """
1213     Pseudo message body class for translating message types on FRRouting.
1214     """
1215
1216
1217 @_FrrZebraMessageBody.register_unknown_type()
1218 @_ZebraMessageBody.register_unknown_type()
1219 class ZebraUnknownMessage(_ZebraMessageBody):
1220     """
1221     Message body class for Unknown command.
1222     """
1223
1224     def __init__(self, buf):
1225         super(ZebraUnknownMessage, self).__init__()
1226         self.buf = buf
1227
1228     @classmethod
1229     def parse(cls, buf, version=_DEFAULT_VERSION):
1230         return cls(buf)
1231
1232     def serialize(self, version=_DEFAULT_VERSION):
1233         return self.buf
1234
1235
1236 @six.add_metaclass(abc.ABCMeta)
1237 class _ZebraInterface(_ZebraMessageBody):
1238     """
1239     Base class for ZEBRA_INTERFACE_ADD, ZEBRA_INTERFACE_DELETE,
1240     ZEBRA_INTERFACE_UP and ZEBRA_INTERFACE_DOWN message body.
1241     """
1242     # Zebra Interface Add/Delete message body:
1243     #  0                   1                   2                   3
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)               |
1247     # |                                                               |
1248     # |                                                               |
1249     # |                                                               |
1250     # |                                                               |
1251     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1252     # | Interface index                                               |
1253     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1254     # | Status        |
1255     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1256     # | Interface flags                                               |
1257     # |                                                               |
1258     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1259     # | (PTM Enable)  | (PTM Status)  | v4(FRRouting)
1260     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1261     # | Metric                                                        |
1262     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1263     # | (Speed): v4(FRRouting v3.0 or later)                          |
1264     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1265     # | Interface's MTU for IPv4                                      |
1266     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1267     # | Interface's MTU for IPv6                                      |
1268     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1269     # | Bandwidth                                                     |
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,
1284     # hw_addr_len
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)
1299
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
1304
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,
1309                  link_params=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
1318         self.speed = speed
1319         self.ifmtu = ifmtu
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
1329
1330     @classmethod
1331     def parse(cls, buf, version=_DEFAULT_VERSION):
1332         ptm_enable = None
1333         ptm_status = None
1334         speed = None
1335         ll_type = None
1336         if version <= 2:
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:]
1341         elif version == 3:
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:]
1346         elif version == 4:
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:]
1357             else:
1358                 raise struct.error(
1359                     'Unsupported FRRouting version: %s'
1360                     % CONF['zapi'].frr_version)
1361         else:
1362             raise struct.error(
1363                 'Unsupported Zebra protocol version: %d'
1364                 % version)
1365         ifname = str(six.text_type(ifname.strip(b'\x00'), 'ascii'))
1366
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))
1374         else:
1375             # Unknown hardware address
1376             hw_addr = hw_addr_bin
1377
1378         if not rest:
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)
1382
1383         (link_param_state,) = struct.unpack_from(cls._LP_STATE_FMT, rest)
1384         rest = rest[cls.LP_STATE_SIZE:]
1385
1386         if link_param_state:
1387             link_params, rest = InterfaceLinkParams.parse(rest)
1388         else:
1389             link_params = None
1390
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,
1394                    link_params)
1395
1396     def serialize(self, version=_DEFAULT_VERSION):
1397         if self.ifname is None:
1398             # Case for sending message to Zebra
1399             return b''
1400         # fixup
1401         if netaddr.valid_mac(self.hw_addr):
1402             # MAC address
1403             hw_addr_len = 6
1404             hw_addr = addrconv.mac.text_to_bin(self.hw_addr)
1405         else:
1406             # Unknown hardware address
1407             hw_addr_len = len(self.hw_addr)
1408             hw_addr = self.hw_addr
1409
1410         if version <= 2:
1411             return struct.pack(
1412                 self._HEADER_FMT,
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
1416         elif version == 3:
1417             buf = struct.pack(
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
1422         elif version == 4:
1423             if _is_frr_version_ge(_FRR_VERSION_3_0):
1424                 buf = struct.pack(
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):
1431                 buf = struct.pack(
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
1437             else:
1438                 raise ValueError(
1439                     'Unsupported FRRouting version: %s'
1440                     % CONF['zapi'].frr_version)
1441         else:
1442             raise ValueError(
1443                 'Unsupported Zebra protocol version: %d'
1444                 % version)
1445
1446         if isinstance(self.link_params, InterfaceLinkParams):
1447             buf += struct.pack(self._LP_STATE_FMT, True)
1448             buf += self.link_params.serialize()
1449         else:
1450             buf += struct.pack(self._LP_STATE_FMT, False)
1451
1452         return buf
1453
1454
1455 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ADD)
1456 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_ADD)
1457 class ZebraInterfaceAdd(_ZebraInterface):
1458     """
1459     Message body class for ZEBRA_INTERFACE_ADD.
1460     """
1461
1462
1463 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_DELETE)
1464 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_DELETE)
1465 class ZebraInterfaceDelete(_ZebraInterface):
1466     """
1467     Message body class for ZEBRA_INTERFACE_DELETE.
1468     """
1469
1470
1471 @six.add_metaclass(abc.ABCMeta)
1472 class _ZebraInterfaceAddress(_ZebraMessageBody):
1473     """
1474     Base class for ZEBRA_INTERFACE_ADDRESS_ADD and
1475     ZEBRA_INTERFACE_ADDRESS_DELETE message body.
1476     """
1477     # Zebra Interface Address Add/Delete message body:
1478     #  0                   1                   2                   3
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
1484     # +-+-+-+-+-+-+-+-+
1485     # | Family        |
1486     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1487     # | IPv4/v6 Prefix (Variable)                                     |
1488     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1489     # | Prefix len    |
1490     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1491     # | IPv4/v6 Destination Address (Variable)                        |
1492     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1493     _HEADER_FMT = '!IB'  # ifindex, ifc_flags
1494     HEADER_SIZE = struct.calcsize(_HEADER_FMT)
1495
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)
1505         self.dest = dest
1506
1507     @classmethod
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:]
1511
1512         (family, prefix, rest) = _parse_zebra_family_prefix(rest)
1513
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)
1518         else:
1519             raise struct.error('Unsupported family: %d' % family)
1520
1521         return cls(ifindex, ifc_flags, family, prefix, dest)
1522
1523     def serialize(self, version=_DEFAULT_VERSION):
1524         (self.family,  # fixup
1525          body_bin) = _serialize_zebra_family_prefix(self.prefix)
1526
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)
1531         else:
1532             raise ValueError(
1533                 'Invalid destination address: %s' % self.dest)
1534
1535         return struct.pack(self._HEADER_FMT,
1536                            self.ifindex, self.ifc_flags) + body_bin
1537
1538
1539 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ADDRESS_ADD)
1540 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_ADDRESS_ADD)
1541 class ZebraInterfaceAddressAdd(_ZebraInterfaceAddress):
1542     """
1543     Message body class for ZEBRA_INTERFACE_ADDRESS_ADD.
1544     """
1545
1546
1547 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ADDRESS_DELETE)
1548 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_ADDRESS_DELETE)
1549 class ZebraInterfaceAddressDelete(_ZebraInterfaceAddress):
1550     """
1551     Message body class for ZEBRA_INTERFACE_ADDRESS_DELETE.
1552     """
1553
1554
1555 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_UP)
1556 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_UP)
1557 class ZebraInterfaceUp(_ZebraInterface):
1558     """
1559     Message body class for ZEBRA_INTERFACE_UP.
1560     """
1561
1562
1563 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_DOWN)
1564 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_DOWN)
1565 class ZebraInterfaceDown(_ZebraInterface):
1566     """
1567     Message body class for ZEBRA_INTERFACE_DOWN.
1568     """
1569
1570
1571 @six.add_metaclass(abc.ABCMeta)
1572 class _ZebraIPRoute(_ZebraMessageBody):
1573     """
1574     Base class for ZEBRA_IPV4_ROUTE_* and ZEBRA_IPV6_ROUTE_*
1575     message body.
1576
1577     .. Note::
1578
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.
1582     """
1583     # Zebra IPv4/IPv6 Route message body (Protocol Daemons -> Zebra Daemon):
1584     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1589     # | SAFI                          |
1590     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1591     # | IPv4/v6 Prefix (Variable)                                     |
1592     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1593     # | Nexthop Num   |
1594     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1595     # | Nexthops (Variable)                                           |
1596     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1597     # | (Distance)    |
1598     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1599     # | (Metric)                                                      |
1600     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1601     # | (MTU)                                                         |
1602     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1603     # | (TAG)                                                         |
1604     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1605     #
1606     # Zebra IPv4/IPv6 Route message body on FRRouting
1607     # (Protocol Daemons -> Zebra Daemon):
1608     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1613     # | Flags                                                         |
1614     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1615     # | Message       | SAFI                          |
1616     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1617     # | IPv4/v6 Prefix (Variable)                                     |
1618     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1619     # | (IPv4/v6 Source Prefix): v4(FRRouting v3.0 or later)          |
1620     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1621     # | Nexthop Num   |
1622     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1623     # | Nexthops (Variable)                                           |
1624     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1625     # | (Distance)    |
1626     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1627     # | (Metric)                                                      |
1628     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1629     # | (TAG)                                                         |
1630     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1631     # | (MTU)                                                         |
1632     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1633     #
1634     # Zebra IPv4/IPv6 Route message body (Zebra Daemon -> Protocol Daemons):
1635     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1642     # | (Nexthop Num) |
1643     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1644     # | (Nexthops (Variable))                                         |
1645     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1646     # | (IFIndex Num) |
1647     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1648     # | (Interface indexes)                                           |
1649     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1650     # | (Distance)    |
1651     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1652     # | (Metric)                                                      |
1653     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1654     # | (MTU)                                                         |
1655     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1656     # | (TAG)                                                         |
1657     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1658     #
1659     # Zebra IPv4/IPv6 Route message body on FRRouting
1660     # (Zebra Daemon -> Protocol Daemons):
1661     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1666     # | Flags                                                         |
1667     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1668     # | Message       |
1669     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1670     # | IPv4/v6 Prefix (Variable)                                     |
1671     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1672     # | (IPv4/v6 Source Prefix): v4(FRRouting v3.0 or later)          |
1673     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1674     # | (Nexthop Num) |
1675     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1676     # | (Nexthops (Variable))                                         |
1677     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1678     # | (IFIndex Num) |
1679     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1680     # | (Interface indexes)                                           |
1681     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1682     # | (Distance)    |
1683     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1684     # | (Metric)                                                      |
1685     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1686     # | (TAG)                                                         |
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)
1698
1699     # API type specific constants
1700     _FAMILY = None  # either socket.AF_INET or socket.AF_INET6
1701
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
1710         self.flags = flags
1711         self.message = message
1712
1713         # SAFI should be included if this message sent to Zebra.
1714         if from_zebra:
1715             self.safi = None
1716         else:
1717             self.safi = safi or packet_safi.UNICAST
1718
1719         assert prefix is not None
1720         if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
1721             prefix = prefix.prefix
1722         self.prefix = prefix
1723
1724         if isinstance(src_prefix, (IPv4Prefix, IPv6Prefix)):
1725             src_prefix = src_prefix.prefix
1726         self.src_prefix = src_prefix
1727
1728         # Nexthops should be a list of str representations of IP address
1729         # if this message sent from Zebra, otherwise a list of _Nexthop
1730         # subclasses.
1731         nexthops = nexthops or []
1732         if from_zebra:
1733             for nexthop in nexthops:
1734                 assert ip.valid_ipv4(nexthop) or ip.valid_ipv6(nexthop)
1735         else:
1736             for nexthop in nexthops:
1737                 assert isinstance(nexthop, _NextHop)
1738         self.nexthops = nexthops
1739
1740         # Interface indexes should be included if this message sent from
1741         # Zebra.
1742         if from_zebra:
1743             ifindexes = ifindexes or []
1744             for ifindex in ifindexes:
1745                 assert isinstance(ifindex, six.integer_types)
1746             self.ifindexes = ifindexes
1747         else:
1748             self.ifindexes = None
1749
1750         self.distance = distance
1751         self.metric = metric
1752         self.mtu = mtu
1753         self.tag = tag
1754
1755         # is this message sent from Zebra message or not.
1756         self.from_zebra = from_zebra
1757
1758     @classmethod
1759     def _parse_message_option(cls, message, flag, fmt, buf):
1760         if message & flag:
1761             (option,) = struct.unpack_from(fmt, buf)
1762             return option, buf[struct.calcsize(fmt):]
1763
1764         return None, buf
1765
1766     @classmethod
1767     def _parse_impl(cls, buf, version=_DEFAULT_VERSION, from_zebra=False):
1768         instance = None
1769         if version <= 3:
1770             (route_type, flags, message,) = struct.unpack_from(
1771                 cls._HEADER_FMT, buf)
1772             rest = buf[cls.HEADER_SIZE:]
1773         elif version == 4:
1774             (route_type, instance, flags, message,) = struct.unpack_from(
1775                 cls._V4_HEADER_FMT, buf)
1776             rest = buf[cls.V4_HEADER_SIZE:]
1777         else:
1778             raise struct.error(
1779                 'Unsupported Zebra protocol version: %d'
1780                 % version)
1781
1782         if from_zebra:
1783             safi = None
1784         else:
1785             (safi,) = struct.unpack_from(cls._SAFI_FMT, rest)
1786             rest = rest[cls.SAFI_SIZE:]
1787
1788         prefix, rest = _parse_ip_prefix(cls._FAMILY, rest)
1789
1790         src_prefix = None
1791         if version == 4 and message & FRR_ZAPI_MESSAGE_SRCPFX:
1792             src_prefix, rest = _parse_ip_prefix(cls._FAMILY, rest)
1793
1794         if from_zebra and message & ZAPI_MESSAGE_NEXTHOP:
1795             nexthops = []
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)
1802                     rest = rest[4:]
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)
1807                     rest = rest[16:]
1808         else:
1809             nexthops, rest = _parse_nexthops(rest, version)
1810
1811         ifindexes = []
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:]
1819
1820         if version <= 3:
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)
1829         elif version == 4:
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)
1838         else:
1839             raise struct.error(
1840                 'Unsupported Zebra protocol version: %d'
1841                 % version)
1842
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)
1847
1848     @classmethod
1849     def parse(cls, buf, version=_DEFAULT_VERSION):
1850         return cls._parse_impl(buf, version=version)
1851
1852     @classmethod
1853     def parse_from_zebra(cls, buf, version=_DEFAULT_VERSION):
1854         return cls._parse_impl(buf, version=version, from_zebra=True)
1855
1856     def _serialize_message_option(self, option, flag, fmt):
1857         if option is None:
1858             return b''
1859
1860         # fixup
1861         self.message |= flag
1862
1863         return struct.pack(fmt, option)
1864
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)
1870
1871         nexthops = b''
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)
1877         else:
1878             self.message |= ZAPI_MESSAGE_NEXTHOP  # fixup
1879             nexthops = _serialize_nexthops(self.nexthops, version=version)
1880
1881         ifindexes = b''
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)
1887
1888         if version <= 3:
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(
1898                 self._HEADER_FMT,
1899                 self.route_type, self.flags, self.message)
1900         elif version == 4:
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)
1912         else:
1913             raise ValueError(
1914                 'Unsupported Zebra protocol version: %d'
1915                 % version)
1916
1917         if not self.from_zebra:
1918             header += struct.pack(self._SAFI_FMT, self.safi)
1919
1920         return header + prefix + nexthops + ifindexes + options
1921
1922
1923 class _ZebraIPv4Route(_ZebraIPRoute):
1924     """
1925     Base class for ZEBRA_IPV4_ROUTE_* message body.
1926     """
1927     _FAMILY = socket.AF_INET
1928
1929
1930 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_ROUTE_ADD)
1931 @_ZebraMessageBody.register_type(ZEBRA_IPV4_ROUTE_ADD)
1932 class ZebraIPv4RouteAdd(_ZebraIPv4Route):
1933     """
1934     Message body class for ZEBRA_IPV4_ROUTE_ADD.
1935     """
1936
1937
1938 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_ROUTE_DELETE)
1939 @_ZebraMessageBody.register_type(ZEBRA_IPV4_ROUTE_DELETE)
1940 class ZebraIPv4RouteDelete(_ZebraIPv4Route):
1941     """
1942     Message body class for ZEBRA_IPV4_ROUTE_DELETE.
1943     """
1944
1945
1946 class _ZebraIPv6Route(_ZebraIPRoute):
1947     """
1948     Base class for ZEBRA_IPV6_ROUTE_* message body.
1949     """
1950     _FAMILY = socket.AF_INET6
1951
1952
1953 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_ROUTE_ADD)
1954 @_ZebraMessageBody.register_type(ZEBRA_IPV6_ROUTE_ADD)
1955 class ZebraIPv6RouteAdd(_ZebraIPv6Route):
1956     """
1957     Message body class for ZEBRA_IPV6_ROUTE_ADD.
1958     """
1959
1960
1961 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_ROUTE_DELETE)
1962 @_ZebraMessageBody.register_type(ZEBRA_IPV6_ROUTE_DELETE)
1963 class ZebraIPv6RouteDelete(_ZebraIPv6Route):
1964     """
1965     Message body class for ZEBRA_IPV6_ROUTE_DELETE.
1966     """
1967
1968
1969 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD)
1970 class ZebraIPv4RouteIPv6NexthopAdd(_ZebraIPv4Route):
1971     """
1972     Message body class for FRR_ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD.
1973     """
1974
1975
1976 @six.add_metaclass(abc.ABCMeta)
1977 class _ZebraRedistribute(_ZebraMessageBody):
1978     """
1979     Base class for ZEBRA_REDISTRIBUTE_ADD and ZEBRA_REDISTRIBUTE_DELETE
1980     message body.
1981     """
1982     # Zebra Redistribute message body:
1983     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1986     # | Route Type    |
1987     # +-+-+-+-+-+-+-+-+
1988     #
1989     # Zebra Redistribute message body on FRRouting:
1990     #  0                   1                   2                   3
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)
1999
2000     def __init__(self, route_type, afi=None, instance=None):
2001         super(_ZebraRedistribute, self).__init__()
2002         self.afi = afi
2003         self.route_type = route_type
2004         self.instance = instance
2005
2006     @classmethod
2007     def parse(cls, buf, version=_DEFAULT_VERSION):
2008         afi = None
2009         instance = None
2010         if version <= 3:
2011             (route_type,) = struct.unpack_from(cls._HEADER_FMT, buf)
2012         elif version == 4:
2013             (afi, route_type,
2014              instance) = struct.unpack_from(cls._V4_HEADER_FMT, buf)
2015         else:
2016             raise struct.error(
2017                 'Unsupported Zebra protocol version: %d'
2018                 % version)
2019
2020         return cls(route_type, afi, instance)
2021
2022     def serialize(self, version=_DEFAULT_VERSION):
2023         if version <= 3:
2024             return struct.pack(self._HEADER_FMT, self.route_type)
2025         elif version == 4:
2026             return struct.pack(self._V4_HEADER_FMT,
2027                                self.afi, self.route_type, self.instance)
2028         else:
2029             raise ValueError(
2030                 'Unsupported Zebra protocol version: %d'
2031                 % version)
2032
2033
2034 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_ADD)
2035 @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_ADD)
2036 class ZebraRedistributeAdd(_ZebraRedistribute):
2037     """
2038     Message body class for ZEBRA_REDISTRIBUTE_ADD.
2039     """
2040
2041
2042 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_DELETE)
2043 @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_DELETE)
2044 class ZebraRedistributeDelete(_ZebraRedistribute):
2045     """
2046     Message body class for ZEBRA_REDISTRIBUTE_DELETE.
2047     """
2048
2049
2050 @six.add_metaclass(abc.ABCMeta)
2051 class _ZebraRedistributeDefault(_ZebraMessageBody):
2052     """
2053     Base class for ZEBRA_REDISTRIBUTE_DEFAULT_ADD and
2054     ZEBRA_REDISTRIBUTE_DEFAULT_DELETE message body.
2055     """
2056
2057
2058 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_DEFAULT_ADD)
2059 @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_DEFAULT_ADD)
2060 class ZebraRedistributeDefaultAdd(_ZebraRedistribute):
2061     """
2062     Message body class for ZEBRA_REDISTRIBUTE_DEFAULT_ADD.
2063     """
2064
2065
2066 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_DEFAULT_DELETE)
2067 @_ZebraMessageBody.register_type(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE)
2068 class ZebraRedistributeDefaultDelete(_ZebraRedistribute):
2069     """
2070     Message body class for ZEBRA_REDISTRIBUTE_DEFAULT_DELETE.
2071     """
2072
2073
2074 @six.add_metaclass(abc.ABCMeta)
2075 class _ZebraIPNexthopLookup(_ZebraMessageBody):
2076     """
2077     Base class for ZEBRA_IPV4_NEXTHOP_LOOKUP and
2078     ZEBRA_IPV6_NEXTHOP_LOOKUP message body.
2079     """
2080     # Zebra IPv4/v6 Nexthop Lookup message body:
2081     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2086     # | Metric                                                        |
2087     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2088     # | Nexthop Num   |
2089     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2090     # | Nexthops (Variable)                                           |
2091     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2092     _METRIC_FMT = '!I'  # metric
2093     METRIC_SIZE = struct.calcsize(_METRIC_FMT)
2094
2095     # Message type specific constants
2096     ADDR_CLS = None  # either addrconv.ipv4 or addrconv.ipv6
2097     ADDR_LEN = None  # IP address length in bytes
2098
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)
2102         self.addr = addr
2103         self.metric = metric
2104         nexthops = nexthops or []
2105         for nexthop in nexthops:
2106             assert isinstance(nexthop, _NextHop)
2107         self.nexthops = nexthops
2108
2109     @classmethod
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:]
2113
2114         metric = None
2115         if rest:
2116             # Note: Case for ZEBRA_IPV4_NEXTHOP_LOOKUP request
2117             (metric,) = struct.unpack_from(cls._METRIC_FMT, rest)
2118             rest = rest[cls.METRIC_SIZE:]
2119
2120         nexthops = None
2121         if rest:
2122             nexthops, rest = _parse_nexthops(rest, version)
2123
2124         return cls(addr, metric, nexthops)
2125
2126     def serialize(self, version=_DEFAULT_VERSION):
2127         buf = self.ADDR_CLS.text_to_bin(self.addr)
2128
2129         if self.metric is None:
2130             return buf
2131
2132         buf += struct.pack(self._METRIC_FMT, self.metric)
2133
2134         return buf + _serialize_nexthops(self.nexthops, version=version)
2135
2136
2137 @_ZebraMessageBody.register_type(ZEBRA_IPV4_NEXTHOP_LOOKUP)
2138 class ZebraIPv4NexthopLookup(_ZebraIPNexthopLookup):
2139     """
2140     Message body class for ZEBRA_IPV4_NEXTHOP_LOOKUP.
2141     """
2142     ADDR_CLS = addrconv.ipv4
2143     ADDR_LEN = 4
2144
2145
2146 @_ZebraMessageBody.register_type(ZEBRA_IPV6_NEXTHOP_LOOKUP)
2147 class ZebraIPv6NexthopLookup(_ZebraIPNexthopLookup):
2148     """
2149     Message body class for ZEBRA_IPV6_NEXTHOP_LOOKUP.
2150     """
2151     ADDR_CLS = addrconv.ipv6
2152     ADDR_LEN = 16
2153
2154
2155 @six.add_metaclass(abc.ABCMeta)
2156 class _ZebraIPImportLookup(_ZebraMessageBody):
2157     """
2158     Base class for ZEBRA_IPV4_IMPORT_LOOKUP and
2159     ZEBRA_IPV6_IMPORT_LOOKUP message body.
2160
2161     .. Note::
2162
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.
2166     """
2167     # Zebra IPv4/v6 Import Lookup message body
2168     # (Protocol Daemons -> Zebra Daemon):
2169     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2172     # | Prefix Len    |
2173     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2174     # | IPv4/v6 Prefix (4 bytes or 16 bytes)                          |
2175     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2176     #
2177     # Zebra IPv4/v6 Import Lookup message body
2178     # (Zebra Daemons -> Protocol Daemon):
2179     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2184     # | Metric                                                        |
2185     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2186     # | Nexthop Num   |
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)
2194
2195     # Message type specific constants
2196     PREFIX_CLS = None  # either addrconv.ipv4 or addrconv.ipv6
2197     PREFIX_LEN = None  # IP prefix length in bytes
2198
2199     def __init__(self, prefix, metric=None, nexthops=None,
2200                  from_zebra=False):
2201         super(_ZebraIPImportLookup, self).__init__()
2202         if not from_zebra:
2203             assert ip.valid_ipv4(prefix) or ip.valid_ipv6(prefix)
2204         else:
2205             if isinstance(prefix, (IPv4Prefix, IPv6Prefix)):
2206                 prefix = prefix.prefix
2207             else:
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
2216
2217     @classmethod
2218     def parse_impl(cls, buf, version=_DEFAULT_VERSION, from_zebra=False):
2219         if not from_zebra:
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)
2224
2225         prefix = cls.PREFIX_CLS.bin_to_text(buf[:cls.PREFIX_LEN])
2226         rest = buf[4:]
2227
2228         (metric,) = struct.unpack_from(cls._METRIC_FMT, rest)
2229         rest = rest[cls.METRIC_SIZE:]
2230
2231         nexthops, rest = _parse_nexthops(rest, version)
2232
2233         return cls(prefix, metric, nexthops, from_zebra=True)
2234
2235     @classmethod
2236     def parse(cls, buf, version=_DEFAULT_VERSION):
2237         return cls.parse_impl(buf, version=version, from_zebra=False)
2238
2239     @classmethod
2240     def parse_from_zebra(cls, buf, version=_DEFAULT_VERSION):
2241         return cls.parse_impl(buf, version=version, from_zebra=True)
2242
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('/')
2247                 return struct.pack(
2248                     self._PREFIX_LEN_FMT,
2249                     int(prefix_len)) + self.PREFIX_CLS.text_to_bin(prefix)
2250             else:
2251                 raise ValueError('Invalid prefix: %s' % self.prefix)
2252
2253         if ip.valid_ipv4(self.prefix) or ip.valid_ipv6(self.prefix):
2254             buf = self.PREFIX_CLS.text_to_bin(self.prefix)
2255         else:
2256             raise ValueError('Invalid prefix: %s' % self.prefix)
2257
2258         buf += struct.pack(self._METRIC_FMT, self.metric)
2259
2260         return buf + _serialize_nexthops(self.nexthops, version=version)
2261
2262
2263 @_ZebraMessageBody.register_type(ZEBRA_IPV4_IMPORT_LOOKUP)
2264 class ZebraIPv4ImportLookup(_ZebraIPImportLookup):
2265     """
2266     Message body class for ZEBRA_IPV4_IMPORT_LOOKUP.
2267     """
2268     PREFIX_CLS = addrconv.ipv4
2269     PREFIX_LEN = 4
2270
2271
2272 @_ZebraMessageBody.register_type(ZEBRA_IPV6_IMPORT_LOOKUP)
2273 class ZebraIPv6ImportLookup(_ZebraIPImportLookup):
2274     """
2275     Message body class for ZEBRA_IPV6_IMPORT_LOOKUP.
2276     """
2277     PREFIX_CLS = addrconv.ipv6
2278     PREFIX_LEN = 16
2279
2280
2281 # Note: Not implemented in quagga/zebra/zserv.c
2282 # @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_RENAME)
2283 # class ZebraInterfaceRename(_ZebraMessageBody):
2284
2285
2286 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_ROUTER_ID_ADD)
2287 @_ZebraMessageBody.register_type(ZEBRA_ROUTER_ID_ADD)
2288 class ZebraRouterIDAdd(_ZebraMessageBody):
2289     """
2290     Message body class for ZEBRA_ROUTER_ID_ADD.
2291     """
2292
2293
2294 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_ROUTER_ID_DELETE)
2295 @_ZebraMessageBody.register_type(ZEBRA_ROUTER_ID_DELETE)
2296 class ZebraRouterIDDelete(_ZebraMessageBody):
2297     """
2298     Message body class for ZEBRA_ROUTER_ID_DELETE.
2299     """
2300
2301
2302 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_ROUTER_ID_UPDATE)
2303 @_ZebraMessageBody.register_type(ZEBRA_ROUTER_ID_UPDATE)
2304 class ZebraRouterIDUpdate(_ZebraMessageBody):
2305     """
2306     Message body class for ZEBRA_ROUTER_ID_UPDATE.
2307     """
2308     # Zebra Router ID Update message body:
2309     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2312     # | Family        |
2313     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2314     # | IPv4/v6 prefix                                                |
2315     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2316     # | Prefix len    |
2317     # +-+-+-+-+-+-+-+-+
2318
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
2325
2326     @classmethod
2327     def parse(cls, buf, version=_DEFAULT_VERSION):
2328         (family, prefix, _) = _parse_zebra_family_prefix(buf)
2329
2330         return cls(family, prefix)
2331
2332     def serialize(self, version=_DEFAULT_VERSION):
2333         (self.family,  # fixup
2334          buf) = _serialize_zebra_family_prefix(self.prefix)
2335
2336         return buf
2337
2338
2339 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_HELLO)
2340 @_ZebraMessageBody.register_type(ZEBRA_HELLO)
2341 class ZebraHello(_ZebraMessageBody):
2342     """
2343     Message body class for ZEBRA_HELLO.
2344     """
2345     # Zebra Hello message body:
2346     #  0                   1                   2                   3
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)
2355
2356     def __init__(self, route_type, instance=None):
2357         super(ZebraHello, self).__init__()
2358         self.route_type = route_type
2359         self.instance = instance
2360
2361     @classmethod
2362     def parse(cls, buf, version=_DEFAULT_VERSION):
2363         instance = None
2364         if version <= 3:
2365             (route_type,) = struct.unpack_from(cls._HEADER_FMT, buf)
2366         elif version == 4:
2367             (route_type,
2368              instance) = struct.unpack_from(cls._V4_HEADER_FMT, buf)
2369         else:
2370             raise struct.error(
2371                 'Unsupported Zebra protocol version: %d'
2372                 % version)
2373
2374         return cls(route_type, instance)
2375
2376     def serialize(self, version=_DEFAULT_VERSION):
2377         if version <= 3:
2378             return struct.pack(self._HEADER_FMT, self.route_type)
2379         elif version == 4:
2380             return struct.pack(self._V4_HEADER_FMT,
2381                                self.route_type, self.instance)
2382         else:
2383             raise ValueError(
2384                 'Unsupported Zebra protocol version: %d'
2385                 % version)
2386
2387
2388 @six.add_metaclass(abc.ABCMeta)
2389 class _ZebraIPNexthopLookupMRib(_ZebraMessageBody):
2390     """
2391     Base class for ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB (and
2392     ZEBRA_IPV6_NEXTHOP_LOOKUP_MRIB) message body.
2393     """
2394     # Zebra IPv4/v6 Nexthop Lookup MRIB message body:
2395     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2400     # | Distance      |
2401     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2402     # | Metric                                                        |
2403     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2404     # | Nexthop Num   |
2405     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2406     # | Nexthops (Variable)                                           |
2407     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2408     _DISTANCE_METRIC_FMT = '!BI'  # distance, metric
2409     DISTANCE_METRIC_SIZE = struct.calcsize(_DISTANCE_METRIC_FMT)
2410
2411     # Message type specific constants
2412     ADDR_CLS = None  # either addrconv.ipv4 or addrconv.ipv6
2413     ADDR_LEN = None  # IP address length in bytes
2414
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)
2418         self.addr = 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
2425
2426     @classmethod
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:]
2430
2431         if not rest:
2432             return cls(addr)
2433
2434         (distance,
2435          metric) = struct.unpack_from(cls._DISTANCE_METRIC_FMT, rest)
2436         rest = rest[cls.DISTANCE_METRIC_SIZE:]
2437
2438         nexthops, rest = _parse_nexthops(rest, version)
2439
2440         return cls(addr, distance, metric, nexthops)
2441
2442     def serialize(self, version=_DEFAULT_VERSION):
2443         buf = self.ADDR_CLS.text_to_bin(self.addr)
2444
2445         if self.distance is None or self.metric is None:
2446             return buf
2447
2448         buf += struct.pack(
2449             self._DISTANCE_METRIC_FMT, self.distance, self.metric)
2450
2451         return buf + _serialize_nexthops(self.nexthops, version=version)
2452
2453
2454 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB)
2455 @_ZebraMessageBody.register_type(ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB)
2456 class ZebraIPv4NexthopLookupMRib(_ZebraIPNexthopLookupMRib):
2457     """
2458     Message body class for ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB.
2459     """
2460     ADDR_CLS = addrconv.ipv4
2461     ADDR_LEN = 4
2462
2463
2464 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_VRF_UNREGISTER)
2465 @_ZebraMessageBody.register_type(ZEBRA_VRF_UNREGISTER)
2466 class ZebraVrfUnregister(_ZebraMessageBody):
2467     """
2468     Message body class for ZEBRA_VRF_UNREGISTER.
2469     """
2470
2471
2472 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_LINK_PARAMS)
2473 @_ZebraMessageBody.register_type(ZEBRA_INTERFACE_LINK_PARAMS)
2474 class ZebraInterfaceLinkParams(_ZebraMessageBody):
2475     """
2476     Message body class for ZEBRA_INTERFACE_LINK_PARAMS.
2477     """
2478     # Zebra Interface Link Parameters message body:
2479     #  0                   1                   2                   3
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
2489
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
2495
2496     @classmethod
2497     def parse(cls, buf, version=_DEFAULT_VERSION):
2498         (ifindex,) = struct.unpack_from(cls._HEADER_FMT, buf)
2499         rest = buf[cls.HEADER_SIZE:]
2500
2501         link_params, rest = InterfaceLinkParams.parse(rest)
2502
2503         return cls(ifindex, link_params)
2504
2505     def serialize(self, version=_DEFAULT_VERSION):
2506         buf = struct.pack(self._HEADER_FMT, self.ifindex)
2507
2508         return buf + self.link_params.serialize()
2509
2510
2511 class _ZebraNexthopRegister(_ZebraMessageBody):
2512     """
2513     Base class for ZEBRA_NEXTHOP_REGISTER and ZEBRA_NEXTHOP_UNREGISTER
2514     message body.
2515     """
2516     # Zebra Nexthop Register message body:
2517     # (Repeat of RegisteredNexthop class)
2518
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
2525
2526     @classmethod
2527     def parse(cls, buf, version=_DEFAULT_VERSION):
2528         nexthops = []
2529         while buf:
2530             nexthop, buf = RegisteredNexthop.parse(buf)
2531             nexthops.append(nexthop)
2532
2533         return cls(nexthops)
2534
2535     def serialize(self, version=_DEFAULT_VERSION):
2536         buf = b''
2537         for nexthop in self.nexthops:
2538             buf += nexthop.serialize()
2539
2540         return buf
2541
2542
2543 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_NEXTHOP_REGISTER)
2544 @_ZebraMessageBody.register_type(ZEBRA_NEXTHOP_REGISTER)
2545 class ZebraNexthopRegister(_ZebraNexthopRegister):
2546     """
2547     Message body class for ZEBRA_NEXTHOP_REGISTER.
2548     """
2549
2550
2551 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_NEXTHOP_UNREGISTER)
2552 @_ZebraMessageBody.register_type(ZEBRA_NEXTHOP_UNREGISTER)
2553 class ZebraNexthopUnregister(_ZebraNexthopRegister):
2554     """
2555     Message body class for ZEBRA_NEXTHOP_UNREGISTER.
2556     """
2557
2558
2559 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_NEXTHOP_UPDATE)
2560 @_ZebraMessageBody.register_type(ZEBRA_NEXTHOP_UPDATE)
2561 class ZebraNexthopUpdate(_ZebraMessageBody):
2562     """
2563     Message body class for ZEBRA_NEXTHOP_UPDATE.
2564     """
2565     # Zebra IPv4/v6 Nexthop Update message body:
2566     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2569     # | Family                        |
2570     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2571     # | IPv4/v6 prefix                                                |
2572     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2573     # | (Distance)    | v4(FRRouting v3.0 or later)
2574     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2575     # | Metric                                                        |
2576     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2577     # | Nexthop Num   |
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)
2587
2588     def __init__(self, family, prefix, distance=None, metric=None,
2589                  nexthops=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
2604
2605     @classmethod
2606     def parse(cls, buf, version=_DEFAULT_VERSION):
2607         (family,) = struct.unpack_from(cls._FAMILY_FMT, buf)
2608         rest = buf[cls.FAMILY_SIZE:]
2609
2610         prefix, rest = _parse_ip_prefix(family, rest)
2611
2612         distance = None
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:]
2616
2617         (metric,) = struct.unpack_from(cls._METRIC_FMT, rest)
2618         rest = rest[cls.METRIC_SIZE:]
2619
2620         nexthops, rest = _parse_nexthops(rest, version)
2621
2622         return cls(family, prefix, distance, metric, nexthops)
2623
2624     def serialize(self, version=_DEFAULT_VERSION):
2625         # fixup
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
2630         else:
2631             raise ValueError('Invalid prefix: %s' % self.prefix)
2632
2633         buf = struct.pack(self._FAMILY_FMT, self.family)
2634
2635         buf += _serialize_ip_prefix(self.prefix)
2636
2637         if _is_frr_version_ge(_FRR_VERSION_3_0):
2638             buf += struct.pack(self._DISTANCE_FMT, self.distance)
2639
2640         buf += struct.pack(self._METRIC_FMT, self.metric)
2641
2642         return buf + _serialize_nexthops(self.nexthops, version=version)
2643
2644
2645 class _ZebraInterfaceNbrAddress(_ZebraMessageBody):
2646     """
2647     Base class for FRR_ZEBRA_INTERFACE_NBR_ADDRESS_* message body.
2648     """
2649     # Zebra Interface Neighbor Address message body:
2650     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2655     # | Family        |
2656     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2657     # | IPv4/v6 prefix                                                |
2658     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2659     # | Prefix len    |
2660     # +-+-+-+-+-+-+-+-+
2661     _HEADER_FMT = '!I'  # ifindex
2662     HEADER_SIZE = struct.calcsize(_HEADER_FMT)
2663
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
2671
2672     @classmethod
2673     def parse(cls, buf, version=_DEFAULT_VERSION):
2674         (ifindex,) = struct.unpack_from(cls._HEADER_FMT, buf)
2675         rest = buf[cls.HEADER_SIZE:]
2676
2677         (family, prefix, _) = _parse_zebra_family_prefix(rest)
2678
2679         return cls(ifindex, family, prefix)
2680
2681     def serialize(self, version=_DEFAULT_VERSION):
2682         (self.family,  # fixup
2683          body_bin) = _serialize_zebra_family_prefix(self.prefix)
2684
2685         return struct.pack(self._HEADER_FMT, self.ifindex) + body_bin
2686
2687
2688 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_NBR_ADDRESS_ADD)
2689 class ZebraInterfaceNbrAddressAdd(_ZebraInterfaceNbrAddress):
2690     """
2691     Message body class for FRR_ZEBRA_INTERFACE_NBR_ADDRESS_ADD.
2692     """
2693
2694
2695 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_NBR_ADDRESS_DELETE)
2696 class ZebraInterfaceNbrAddressDelete(_ZebraInterfaceNbrAddress):
2697     """
2698     Message body class for FRR_ZEBRA_INTERFACE_NBR_ADDRESS_DELETE.
2699     """
2700
2701
2702 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE)
2703 class ZebraInterfaceBfdDestinationUpdate(_ZebraMessageBody):
2704     """
2705     Message body class for FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE.
2706     """
2707     # Zebra Interface BFD Destination Update message body:
2708     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2713     # | Dst Family    |
2714     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2715     # | Dst IPv4/v6 prefix                                            |
2716     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2717     # | Dst Plen      |
2718     # +-+-+-+-+-+-+-+-+
2719     # | Status        |
2720     # +-+-+-+-+-+-+-+-+
2721     # | Src Family    |
2722     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2723     # | Source IPv4/v6 prefix                                         |
2724     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2725     # | Src Plen      |
2726     # +-+-+-+-+-+-+-+-+
2727     _HEADER_FMT = '!I'  # ifindex
2728     HEADER_SIZE = struct.calcsize(_HEADER_FMT)
2729     _STATUS_FMT = '!B'  # status
2730     STATUS_SIZE = struct.calcsize(_STATUS_FMT)
2731
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
2745
2746     @classmethod
2747     def parse(cls, buf, version=_DEFAULT_VERSION):
2748         (ifindex,) = struct.unpack_from(cls._HEADER_FMT, buf)
2749         rest = buf[cls.HEADER_SIZE:]
2750
2751         (dst_family, dst_prefix,
2752          rest) = _parse_zebra_family_prefix(rest)
2753
2754         (status,) = struct.unpack_from(cls._STATUS_FMT, rest)
2755         rest = rest[cls.STATUS_SIZE:]
2756
2757         (src_family, src_prefix,
2758          _) = _parse_zebra_family_prefix(rest)
2759
2760         return cls(ifindex, dst_family, dst_prefix, status,
2761                    src_family, src_prefix)
2762
2763     def serialize(self, version=_DEFAULT_VERSION):
2764         (self.dst_family,  # fixup
2765          dst_bin) = _serialize_zebra_family_prefix(self.dst_prefix)
2766
2767         status_bin = struct.pack(
2768             self._STATUS_FMT, self.status)
2769
2770         (self.src_family,  # fixup
2771          src_bin) = _serialize_zebra_family_prefix(self.src_prefix)
2772
2773         return struct.pack(
2774             self._HEADER_FMT,
2775             self.ifindex) + dst_bin + status_bin + src_bin
2776
2777
2778 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IMPORT_ROUTE_REGISTER)
2779 class ZebraImportRouteRegister(_ZebraNexthopRegister):
2780     """
2781     Message body class for FRR_ZEBRA_IMPORT_ROUTE_REGISTER.
2782     """
2783
2784
2785 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IMPORT_ROUTE_UNREGISTER)
2786 class ZebraImportRouteUnregister(_ZebraNexthopRegister):
2787     """
2788     Message body class for FRR_ZEBRA_IMPORT_ROUTE_UNREGISTER.
2789     """
2790
2791
2792 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IMPORT_CHECK_UPDATE)
2793 class ZebraImportCheckUpdate(ZebraNexthopUpdate):
2794     """
2795     Message body class for FRR_ZEBRA_IMPORT_CHECK_UPDATE.
2796     """
2797
2798
2799 class _ZebraBfdDestination(_ZebraMessageBody):
2800     """
2801     Base class for FRR_ZEBRA_BFD_DEST_REGISTER and
2802     FRR_ZEBRA_BFD_DEST_UPDATE message body.
2803     """
2804     # Zebra BFD Destination message body:
2805     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2808     # | PID                                                           |
2809     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2810     # | Destination Family            |
2811     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2812     # | Destination IPv4/v6 prefix (4 bytes or 16 bytes)              |
2813     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2814     # | Min RX Timer                                                  |
2815     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2816     # | Min TX Timer                                                  |
2817     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2818     # | Detect Mult   |
2819     # +-+-+-+-+-+-+-+-+
2820     # | Multi Hop     |
2821     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2822     # | Source Family                 |
2823     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2824     # | Source IPv4/v6 prefix  (4 bytes or 16 bytes)                  |
2825     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2826     # | (MultiHopCnt) | if Multi Hop enabled
2827     # +-+-+-+-+-+-+-+-+
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)
2834     _FAMILY_FMT = '!H'
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)
2840
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__()
2846         self.pid = pid
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
2859
2860     @classmethod
2861     def _parse_family_prefix(cls, buf):
2862         (family,) = struct.unpack_from(cls._FAMILY_FMT, buf)
2863         rest = buf[cls.FAMILY_SIZE:]
2864
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:]
2869
2870         raise struct.error('Unsupported family: %d' % family)
2871
2872     @classmethod
2873     def parse(cls, buf, version=_DEFAULT_VERSION):
2874         (pid,) = struct.unpack_from(cls._HEADER_FMT, buf)
2875         rest = buf[cls.HEADER_SIZE:]
2876
2877         (dst_family, dst_prefix,
2878          rest) = cls._parse_family_prefix(rest)
2879
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:]
2883
2884         (src_family, src_prefix,
2885          rest) = cls._parse_family_prefix(rest)
2886
2887         multi_hop_count = None
2888         ifname = None
2889         if multi_hop:
2890             (multi_hop_count,) = struct.unpack_from(cls._FOOTER_FMT, rest)
2891         else:
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'))
2895
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)
2900
2901     def _serialize_family_prefix(self, prefix):
2902         if ip.valid_ipv4(prefix):
2903             family = socket.AF_INET
2904             return (family,
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
2909             return (family,
2910                     struct.pack(self._FAMILY_FMT, family)
2911                     + addrconv.ipv6.text_to_bin(prefix))
2912
2913         raise ValueError('Invalid prefix: %s' % prefix)
2914
2915     def serialize(self, version=_DEFAULT_VERSION):
2916         (self.dst_family,  # fixup
2917          dst_bin) = self._serialize_family_prefix(self.dst_prefix)
2918
2919         body_bin = struct.pack(
2920             self._BODY_FMT,
2921             self.min_rx_timer, self.min_tx_timer, self.detect_mult,
2922             self.multi_hop)
2923
2924         (self.src_family,  # fixup
2925          src_bin) = self._serialize_family_prefix(self.src_prefix)
2926
2927         if self.multi_hop:
2928             footer_bin = struct.pack(
2929                 self._FOOTER_FMT, self.multi_hop_count)
2930         else:
2931             ifname_bin = self.ifname.encode('ascii')
2932             footer_bin = struct.pack(
2933                 self._FOOTER_FMT, len(ifname_bin)) + ifname_bin
2934
2935         return struct.pack(
2936             self._HEADER_FMT,
2937             self.pid) + dst_bin + body_bin + src_bin + footer_bin
2938
2939
2940 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_REGISTER)
2941 class ZebraBfdDestinationRegister(_ZebraBfdDestination):
2942     """
2943     Message body class for FRR_ZEBRA_BFD_DEST_REGISTER.
2944     """
2945
2946
2947 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_DEREGISTER)
2948 class ZebraBfdDestinationDeregister(_ZebraMessageBody):
2949     """
2950     Message body class for FRR_ZEBRA_BFD_DEST_DEREGISTER.
2951     """
2952     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2955     # | PID                                                           |
2956     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2957     # | Family                        |
2958     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2959     # | Destination IPv4/v6 prefix (4 bytes or 16 bytes)              |
2960     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2961     # | Multi Hop     |
2962     # +-+-+-+-+-+-+-+-+
2963     # | Family        |
2964     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2965     # | Source IPv4/v6 prefix  (4 bytes or 16 bytes)                  |
2966     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2967     # | (MultiHopCnt) | if Multi Hop enabled
2968     # +-+-+-+-+-+-+-+-+
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)
2975     _FAMILY_FMT = '!H'
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)
2981
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__()
2986         self.pid = pid
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
2996
2997     @classmethod
2998     def _parse_family_prefix(cls, buf):
2999         (family,) = struct.unpack_from(cls._FAMILY_FMT, buf)
3000         rest = buf[cls.FAMILY_SIZE:]
3001
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:]
3006
3007         raise struct.error('Unsupported family: %d' % family)
3008
3009     @classmethod
3010     def parse(cls, buf, version=_DEFAULT_VERSION):
3011         (pid,) = struct.unpack_from(cls._HEADER_FMT, buf)
3012         rest = buf[cls.HEADER_SIZE:]
3013
3014         (dst_family, dst_prefix,
3015          rest) = cls._parse_family_prefix(rest)
3016
3017         (multi_hop,) = struct.unpack_from(cls._BODY_FMT, rest)
3018         rest = rest[cls.BODY_SIZE:]
3019
3020         (src_family, src_prefix,
3021          rest) = cls._parse_family_prefix(rest)
3022
3023         multi_hop_count = None
3024         ifname = None
3025         if multi_hop:
3026             (multi_hop_count,) = struct.unpack_from(cls._FOOTER_FMT, rest)
3027         else:
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'))
3031
3032         return cls(pid, dst_family, dst_prefix,
3033                    multi_hop, src_family, src_prefix,
3034                    multi_hop_count, ifname)
3035
3036     def _serialize_family_prefix(self, prefix):
3037         if ip.valid_ipv4(prefix):
3038             family = socket.AF_INET
3039             return (family,
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
3044             return (family,
3045                     struct.pack(self._FAMILY_FMT, family)
3046                     + addrconv.ipv6.text_to_bin(prefix))
3047
3048         raise ValueError('Invalid prefix: %s' % prefix)
3049
3050     def serialize(self, version=_DEFAULT_VERSION):
3051         (self.dst_family,  # fixup
3052          dst_bin) = self._serialize_family_prefix(self.dst_prefix)
3053
3054         body_bin = struct.pack(self._BODY_FMT, self.multi_hop)
3055
3056         (self.src_family,  # fixup
3057          src_bin) = self._serialize_family_prefix(self.src_prefix)
3058
3059         if self.multi_hop:
3060             footer_bin = struct.pack(
3061                 self._FOOTER_FMT, self.multi_hop_count)
3062         else:
3063             ifname_bin = self.ifname.encode('ascii')
3064             footer_bin = struct.pack(
3065                 self._FOOTER_FMT, len(ifname_bin)) + ifname_bin
3066
3067         return struct.pack(
3068             self._HEADER_FMT,
3069             self.pid) + dst_bin + body_bin + src_bin + footer_bin
3070
3071
3072 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_UPDATE)
3073 class ZebraBfdDestinationUpdate(_ZebraBfdDestination):
3074     """
3075     Message body class for FRR_ZEBRA_BFD_DEST_UPDATE.
3076     """
3077
3078
3079 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_DEST_REPLAY)
3080 class ZebraBfdDestinationReply(_ZebraMessageBody):
3081     """
3082     Message body class for FRR_ZEBRA_BFD_DEST_REPLAY.
3083     """
3084
3085
3086 class _ZebraRedistributeIPv4(_ZebraIPRoute):
3087     """
3088     Base class for FRR_ZEBRA_REDISTRIBUTE_IPV4_* message body.
3089     """
3090     _FAMILY = socket.AF_INET
3091
3092
3093 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV4_ADD)
3094 class ZebraRedistributeIPv4Add(_ZebraRedistributeIPv4):
3095     """
3096     Message body class for FRR_ZEBRA_IPV4_ROUTE_ADD.
3097     """
3098
3099
3100 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV4_DEL)
3101 class ZebraRedistributeIPv4Delete(_ZebraRedistributeIPv4):
3102     """
3103     Message body class for FRR_ZEBRA_IPV4_ROUTE_DELETE.
3104     """
3105
3106
3107 class _ZebraRedistributeIPv6(_ZebraIPRoute):
3108     """
3109     Base class for FRR_ZEBRA_REDISTRIBUTE_IPV6_* message body.
3110     """
3111     _FAMILY = socket.AF_INET6
3112
3113
3114 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV6_ADD)
3115 class ZebraRedistributeIPv6Add(_ZebraRedistributeIPv6):
3116     """
3117     Message body class for FRR_ZEBRA_REDISTRIBUTE_IPV6_ADD.
3118     """
3119
3120
3121 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_REDISTRIBUTE_IPV6_DEL)
3122 class ZebraRedistributeIPv6Delete(_ZebraRedistributeIPv6):
3123     """
3124     Message body class for FRR_ZEBRA_REDISTRIBUTE_IPV6_DEL.
3125     """
3126
3127
3128 class _ZebraVrf(_ZebraMessageBody):
3129     """
3130     Base class for FRR_ZEBRA_VRF_ADD and FRR_ZEBRA_VRF_DELETE message body.
3131     """
3132     # Zebra VRF Add/Delete message body:
3133     #  0                   1                   2                   3
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
3139
3140     def __init__(self, vrf_name):
3141         super(_ZebraVrf, self).__init__()
3142         self.vrf_name = vrf_name
3143
3144     @classmethod
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'))
3148
3149         return cls(vrf_name)
3150
3151     def serialize(self, version=_DEFAULT_FRR_VERSION):
3152         return struct.pack(self._HEADER_FMT, self.vrf_name.encode('ascii'))
3153
3154
3155 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_VRF_ADD)
3156 class ZebraVrfAdd(_ZebraVrf):
3157     """
3158     Message body class for FRR_ZEBRA_VRF_ADD.
3159     """
3160
3161
3162 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_VRF_DELETE)
3163 class ZebraVrfDelete(_ZebraVrf):
3164     """
3165     Message body class for FRR_ZEBRA_VRF_DELETE.
3166     """
3167
3168
3169 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_VRF_UPDATE)
3170 class ZebraInterfaceVrfUpdate(_ZebraMessageBody):
3171     """
3172     Message body class for FRR_ZEBRA_INTERFACE_VRF_UPDATE.
3173     """
3174     # Zebra Interface VRF Update message body:
3175     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3180     # | VRF ID                        |
3181     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3182     _HEADER_FMT = '!IH'  # ifindex, vrf_id
3183
3184     def __init__(self, ifindex, vrf_id):
3185         super(ZebraInterfaceVrfUpdate, self).__init__()
3186         self.ifindex = ifindex
3187         self.vrf_id = vrf_id
3188
3189     @classmethod
3190     def parse(cls, buf, version=_DEFAULT_FRR_VERSION):
3191         (ifindex, vrf_id) = struct.unpack_from(cls._HEADER_FMT, buf)
3192
3193         return cls(ifindex, vrf_id)
3194
3195     def serialize(self, version=_DEFAULT_FRR_VERSION):
3196         return struct.pack(self._HEADER_FMT, self.ifindex, self.vrf_id)
3197
3198
3199 class _ZebraBfdClient(_ZebraMessageBody):
3200     """
3201     Base class for FRR_ZEBRA_BFD_CLIENT_*.
3202     """
3203     # Zebra BFD Client message body:
3204     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3207     # | PID                                                           |
3208     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3209     _HEADER_FMT = '!I'  # pid
3210     HEADER_SIZE = struct.calcsize(_HEADER_FMT)
3211
3212     def __init__(self, pid):
3213         super(_ZebraBfdClient, self).__init__()
3214         self.pid = pid
3215
3216     @classmethod
3217     def parse(cls, buf, version=_DEFAULT_FRR_VERSION):
3218         (pid,) = struct.unpack_from(cls._HEADER_FMT, buf)
3219
3220         return cls(pid)
3221
3222     def serialize(self, version=_DEFAULT_FRR_VERSION):
3223         return struct.pack(self._HEADER_FMT, self.pid)
3224
3225
3226 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_BFD_CLIENT_REGISTER)
3227 class ZebraBfdClientRegister(_ZebraBfdClient):
3228     """
3229     Message body class for FRR_ZEBRA_BFD_CLIENT_REGISTER.
3230     """
3231
3232
3233 class _ZebraInterfaceRadv(_ZebraMessageBody):
3234     """
3235     Base class for FRR_ZEBRA_INTERFACE_*_RADV message body.
3236     """
3237     # Zebra interface Router Advertisement message body:
3238     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3243     # | RA Interval                                                   |
3244     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3245     _HEADER_FMT = '!II'  # ifindex, interval
3246     HEADER_SIZE = struct.calcsize(_HEADER_FMT)
3247
3248     def __init__(self, ifindex, interval):
3249         super(_ZebraInterfaceRadv, self).__init__()
3250         self.ifindex = ifindex
3251         self.interval = interval
3252
3253     @classmethod
3254     def parse(cls, buf, version=_DEFAULT_FRR_VERSION):
3255         (ifindex, interval,) = struct.unpack_from(cls._HEADER_FMT, buf)
3256
3257         return cls(ifindex, interval)
3258
3259     def serialize(self, version=_DEFAULT_FRR_VERSION):
3260         return struct.pack(self._HEADER_FMT, self.ifindex, self.interval)
3261
3262
3263 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_ENABLE_RADV)
3264 class ZebraInterfaceEnableRadv(_ZebraInterfaceRadv):
3265     """
3266     Message body class for FRR_ZEBRA_INTERFACE_ENABLE_RADV.
3267     """
3268
3269
3270 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_DISABLE_RADV)
3271 class ZebraInterfaceDisableRadv(_ZebraInterfaceRadv):
3272     """
3273     Message body class for FRR_ZEBRA_INTERFACE_DISABLE_RADV.
3274     """
3275
3276
3277 class _ZebraMplsLabels(_ZebraMessageBody):
3278     """
3279     Base class for ZEBRA_MPLS_LABELS_* message body.
3280     """
3281     # Zebra MPLS Labels message body:
3282     #  0                   1                   2                   3
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     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3285     # | Route Type    |
3286     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3287     # | Family                                                        |
3288     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3289     # | IPv4/v6 Prefix (4 bytes/16 bytes)                             |
3290     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3291     # | Prefix Len    |
3292     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3293     # | Gate IPv4/v6 Address (4 bytes/16 bytes)                       |
3294     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3295     # | Interface Index: v4(FRRouting v3.0 or later)                  |
3296     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3297     # | Distance      |
3298     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3299     # | In Label                                                      |
3300     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3301     # | Out Label                                                     |
3302     # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3303     _HEADER_FMT = '!B'  # route_type
3304     HEADER_SIZE = struct.calcsize(_HEADER_FMT)
3305     _FAMILY_FMT = '!I'
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'
3313     _IFINDEX_FMT = '!I'
3314     IFINDEX_SIZE = struct.calcsize(_IFINDEX_FMT)
3315     _BODY_FMT = '!BII'  # distance, in_label, out_label
3316
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
3336
3337     @classmethod
3338     def _parse_family_prefix(cls, buf):
3339         (family,) = struct.unpack_from(cls._FAMILY_FMT, buf)
3340         rest = buf[cls.FAMILY_SIZE:]
3341
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:]
3350         else:
3351             raise struct.error('Unsupported family: %d' % family)
3352
3353         return family, prefix, rest
3354
3355     @classmethod
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:]
3359
3360         (family, prefix, rest) = cls._parse_family_prefix(rest)
3361
3362         if family == socket.AF_INET:
3363             gate_addr = addrconv.ipv4.bin_to_text(rest[:4])
3364             rest = rest[4:]
3365         elif family == socket.AF_INET6:
3366             gate_addr = addrconv.ipv6.bin_to_text(rest[:16])
3367             rest = rest[16:]
3368         else:
3369             raise struct.error('Unsupported family: %d' % family)
3370
3371         ifindex = None
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:]
3375
3376         (distance, in_label,
3377          out_label) = struct.unpack_from(cls._BODY_FMT, rest)
3378
3379         return cls(route_type, family, prefix, gate_addr, ifindex,
3380                    distance, in_label, out_label)
3381
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,
3388                 family,
3389                 addrconv.ipv4.text_to_bin(prefix_addr),
3390                 int(prefix_num))
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,
3396                 family,
3397                 addrconv.ipv6.text_to_bin(prefix_addr),
3398                 int(prefix_num))
3399
3400         raise ValueError('Invalid prefix: %s' % prefix)
3401
3402     def serialize(self, version=_DEFAULT_FRR_VERSION):
3403         (self.family,  # fixup
3404          prefix_bin) = self._serialize_family_prefix(self.prefix)
3405
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)
3410         else:
3411             raise ValueError('Unsupported family: %d' % self.family)
3412
3413         body_bin = b''
3414         if _is_frr_version_ge(_FRR_VERSION_3_0):
3415             body_bin = struct.pack(self._IFINDEX_FMT, self.ifindex)
3416
3417         body_bin += struct.pack(
3418             self._BODY_FMT, self.distance, self.in_label, self.out_label)
3419
3420         return struct.pack(
3421             self._HEADER_FMT,
3422             self.route_type) + prefix_bin + gate_addr_bin + body_bin
3423
3424
3425 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_MPLS_LABELS_ADD)
3426 class ZebraMplsLabelsAdd(_ZebraMplsLabels):
3427     """
3428     Message body class for FRR_ZEBRA_MPLS_LABELS_ADD.
3429     """
3430
3431
3432 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_MPLS_LABELS_DELETE)
3433 class ZebraMplsLabelsDelete(_ZebraMplsLabels):
3434     """
3435     Message body class for FRR_ZEBRA_MPLS_LABELS_DELETE.
3436     """
3437
3438
3439 class _ZebraIPv4Nexthop(_ZebraIPRoute):
3440     """
3441     Base class for FRR_ZEBRA_IPV4_NEXTHOP_* message body.
3442     """
3443     _FAMILY = socket.AF_INET
3444
3445
3446 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_NEXTHOP_ADD)
3447 class ZebraIPv4NexthopAdd(_ZebraIPv4Nexthop):
3448     """
3449     Message body class for FRR_ZEBRA_IPV4_NEXTHOP_ADD.
3450     """
3451
3452
3453 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV4_NEXTHOP_DELETE)
3454 class ZebraIPv4NexthopDelete(_ZebraIPv4Nexthop):
3455     """
3456     Message body class for FRR_ZEBRA_IPV4_NEXTHOP_DELETE.
3457     """
3458
3459
3460 class _ZebraIPv6Nexthop(_ZebraIPRoute):
3461     """
3462     Base class for FRR_ZEBRA_IPV6_NEXTHOP_* message body.
3463     """
3464     _FAMILY = socket.AF_INET6
3465
3466
3467 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_NEXTHOP_ADD)
3468 class ZebraIPv6NexthopAdd(_ZebraIPv6Nexthop):
3469     """
3470     Message body class for FRR_ZEBRA_IPV6_NEXTHOP_ADD.
3471     """
3472
3473
3474 @_FrrZebraMessageBody.register_type(FRR_ZEBRA_IPV6_NEXTHOP_DELETE)
3475 class ZebraIPv6NexthopDelete(_ZebraIPv6Nexthop):
3476     """
3477     Message body class for FRR_ZEBRA_IPV6_NEXTHOP_DELETE.
3478     """