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""" 17Zebra protocol parser/serializer 18 19Zebra Protocol is used to communicate with the zebra daemon. 20""" 21 22import abc 23import socket 24import struct 25import logging 26from distutils.version import LooseVersion 27 28import netaddr 29import six 30 31from ryu import flags as cfg_flags # For loading 'zapi' option definition 32from ryu.cfg import CONF 33from ryu.lib import addrconv 34from ryu.lib import ip 35from ryu.lib import stringify 36from ryu.lib import type_desc 37from . import packet_base 38from . import bgp 39from . import safi as packet_safi 40 41 42LOG = 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 54ZEBRA_PORT = 2600 55 56# Zebra message types 57ZEBRA_INTERFACE_ADD = 1 58ZEBRA_INTERFACE_DELETE = 2 59ZEBRA_INTERFACE_ADDRESS_ADD = 3 60ZEBRA_INTERFACE_ADDRESS_DELETE = 4 61ZEBRA_INTERFACE_UP = 5 62ZEBRA_INTERFACE_DOWN = 6 63ZEBRA_IPV4_ROUTE_ADD = 7 64ZEBRA_IPV4_ROUTE_DELETE = 8 65ZEBRA_IPV6_ROUTE_ADD = 9 66ZEBRA_IPV6_ROUTE_DELETE = 10 67ZEBRA_REDISTRIBUTE_ADD = 11 68ZEBRA_REDISTRIBUTE_DELETE = 12 69ZEBRA_REDISTRIBUTE_DEFAULT_ADD = 13 70ZEBRA_REDISTRIBUTE_DEFAULT_DELETE = 14 71ZEBRA_IPV4_NEXTHOP_LOOKUP = 15 72ZEBRA_IPV6_NEXTHOP_LOOKUP = 16 73ZEBRA_IPV4_IMPORT_LOOKUP = 17 74ZEBRA_IPV6_IMPORT_LOOKUP = 18 75ZEBRA_INTERFACE_RENAME = 19 76ZEBRA_ROUTER_ID_ADD = 20 77ZEBRA_ROUTER_ID_DELETE = 21 78ZEBRA_ROUTER_ID_UPDATE = 22 79ZEBRA_HELLO = 23 80ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB = 24 81ZEBRA_VRF_UNREGISTER = 25 82ZEBRA_INTERFACE_LINK_PARAMS = 26 83ZEBRA_NEXTHOP_REGISTER = 27 84ZEBRA_NEXTHOP_UNREGISTER = 28 85ZEBRA_NEXTHOP_UPDATE = 29 86ZEBRA_MESSAGE_MAX = 30 87 88# Zebra message types on FRRouting 89FRR_ZEBRA_INTERFACE_ADD = 0 90FRR_ZEBRA_INTERFACE_DELETE = 1 91FRR_ZEBRA_INTERFACE_ADDRESS_ADD = 2 92FRR_ZEBRA_INTERFACE_ADDRESS_DELETE = 3 93FRR_ZEBRA_INTERFACE_UP = 4 94FRR_ZEBRA_INTERFACE_DOWN = 5 95FRR_ZEBRA_IPV4_ROUTE_ADD = 6 96FRR_ZEBRA_IPV4_ROUTE_DELETE = 7 97FRR_ZEBRA_IPV6_ROUTE_ADD = 8 98FRR_ZEBRA_IPV6_ROUTE_DELETE = 9 99FRR_ZEBRA_REDISTRIBUTE_ADD = 10 100FRR_ZEBRA_REDISTRIBUTE_DELETE = 11 101FRR_ZEBRA_REDISTRIBUTE_DEFAULT_ADD = 12 102FRR_ZEBRA_REDISTRIBUTE_DEFAULT_DELETE = 13 103FRR_ZEBRA_ROUTER_ID_ADD = 14 104FRR_ZEBRA_ROUTER_ID_DELETE = 15 105FRR_ZEBRA_ROUTER_ID_UPDATE = 16 106FRR_ZEBRA_HELLO = 17 107FRR_ZEBRA_NEXTHOP_REGISTER = 18 108FRR_ZEBRA_NEXTHOP_UNREGISTER = 19 109FRR_ZEBRA_NEXTHOP_UPDATE = 20 110FRR_ZEBRA_INTERFACE_NBR_ADDRESS_ADD = 21 111FRR_ZEBRA_INTERFACE_NBR_ADDRESS_DELETE = 22 112FRR_ZEBRA_INTERFACE_BFD_DEST_UPDATE = 23 113FRR_ZEBRA_IMPORT_ROUTE_REGISTER = 24 114FRR_ZEBRA_IMPORT_ROUTE_UNREGISTER = 25 115FRR_ZEBRA_IMPORT_CHECK_UPDATE = 26 116FRR_ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD = 27 117FRR_ZEBRA_BFD_DEST_REGISTER = 28 118FRR_ZEBRA_BFD_DEST_DEREGISTER = 29 119FRR_ZEBRA_BFD_DEST_UPDATE = 30 120FRR_ZEBRA_BFD_DEST_REPLAY = 31 121FRR_ZEBRA_REDISTRIBUTE_IPV4_ADD = 32 122FRR_ZEBRA_REDISTRIBUTE_IPV4_DEL = 33 123FRR_ZEBRA_REDISTRIBUTE_IPV6_ADD = 34 124FRR_ZEBRA_REDISTRIBUTE_IPV6_DEL = 35 125FRR_ZEBRA_VRF_UNREGISTER = 36 126FRR_ZEBRA_VRF_ADD = 37 127FRR_ZEBRA_VRF_DELETE = 38 128FRR_ZEBRA_INTERFACE_VRF_UPDATE = 39 129FRR_ZEBRA_BFD_CLIENT_REGISTER = 40 130FRR_ZEBRA_INTERFACE_ENABLE_RADV = 41 131FRR_ZEBRA_INTERFACE_DISABLE_RADV = 42 132FRR_ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB = 43 133FRR_ZEBRA_INTERFACE_LINK_PARAMS = 44 134FRR_ZEBRA_MPLS_LABELS_ADD = 45 135FRR_ZEBRA_MPLS_LABELS_DELETE = 46 136FRR_ZEBRA_IPV4_NEXTHOP_ADD = 47 137FRR_ZEBRA_IPV4_NEXTHOP_DELETE = 48 138FRR_ZEBRA_IPV6_NEXTHOP_ADD = 49 139FRR_ZEBRA_IPV6_NEXTHOP_DELETE = 50 140 141# Zebra route types 142ZEBRA_ROUTE_SYSTEM = 0 143ZEBRA_ROUTE_KERNEL = 1 144ZEBRA_ROUTE_CONNECT = 2 145ZEBRA_ROUTE_STATIC = 3 146ZEBRA_ROUTE_RIP = 4 147ZEBRA_ROUTE_RIPNG = 5 148ZEBRA_ROUTE_OSPF = 6 149ZEBRA_ROUTE_OSPF6 = 7 150ZEBRA_ROUTE_ISIS = 8 151ZEBRA_ROUTE_BGP = 9 152ZEBRA_ROUTE_PIM = 10 153ZEBRA_ROUTE_HSLS = 11 154ZEBRA_ROUTE_OLSR = 12 155ZEBRA_ROUTE_BABEL = 13 156ZEBRA_ROUTE_MAX = 14 157 158# Zebra route types on FRRouting 159FRR_ZEBRA_ROUTE_SYSTEM = 0 160FRR_ZEBRA_ROUTE_KERNEL = 1 161FRR_ZEBRA_ROUTE_CONNECT = 2 162FRR_ZEBRA_ROUTE_STATIC = 3 163FRR_ZEBRA_ROUTE_RIP = 4 164FRR_ZEBRA_ROUTE_RIPNG = 5 165FRR_ZEBRA_ROUTE_OSPF = 6 166FRR_ZEBRA_ROUTE_OSPF6 = 7 167FRR_ZEBRA_ROUTE_ISIS = 8 168FRR_ZEBRA_ROUTE_BGP = 9 169FRR_ZEBRA_ROUTE_PIM = 10 170FRR_ZEBRA_ROUTE_HSLS = 11 171FRR_ZEBRA_ROUTE_OLSR = 12 172FRR_ZEBRA_ROUTE_TABLE = 13 173FRR_ZEBRA_ROUTE_LDP = 14 174FRR_ZEBRA_ROUTE_VNC = 15 175FRR_ZEBRA_ROUTE_VNC_DIRECT = 16 176FRR_ZEBRA_ROUTE_VNC_DIRECT_RH = 17 177FRR_ZEBRA_ROUTE_BGP_DIRECT = 18 178FRR_ZEBRA_ROUTE_BGP_DIRECT_EXT = 19 179FRR_ZEBRA_ROUTE_ALL = 20 180FRR_ZEBRA_ROUTE_MAX = 21 181 182# Zebra message flags 183ZEBRA_FLAG_INTERNAL = 0x01 184ZEBRA_FLAG_SELFROUTE = 0x02 185ZEBRA_FLAG_BLACKHOLE = 0x04 186ZEBRA_FLAG_IBGP = 0x08 187ZEBRA_FLAG_SELECTED = 0x10 188ZEBRA_FLAG_FIB_OVERRIDE = 0x20 189ZEBRA_FLAG_STATIC = 0x40 190ZEBRA_FLAG_REJECT = 0x80 191 192# Zebra message flags on FRRouting 193FRR_ZEBRA_FLAG_INTERNAL = 0x01 194FRR_ZEBRA_FLAG_SELFROUTE = 0x02 195FRR_ZEBRA_FLAG_BLACKHOLE = 0x04 196FRR_ZEBRA_FLAG_IBGP = 0x08 197FRR_ZEBRA_FLAG_SELECTED = 0x10 198FRR_ZEBRA_FLAG_STATIC = 0x40 199FRR_ZEBRA_FLAG_REJECT = 0x80 200FRR_ZEBRA_FLAG_SCOPE_LINK = 0x100 201FRR_ZEBRA_FLAG_FIB_OVERRIDE = 0x200 202 203# Zebra nexthop flags 204ZEBRA_NEXTHOP_IFINDEX = 1 205ZEBRA_NEXTHOP_IFNAME = 2 206ZEBRA_NEXTHOP_IPV4 = 3 207ZEBRA_NEXTHOP_IPV4_IFINDEX = 4 208ZEBRA_NEXTHOP_IPV4_IFNAME = 5 209ZEBRA_NEXTHOP_IPV6 = 6 210ZEBRA_NEXTHOP_IPV6_IFINDEX = 7 211ZEBRA_NEXTHOP_IPV6_IFNAME = 8 212ZEBRA_NEXTHOP_BLACKHOLE = 9 213 214# Zebra nexthop flags on FRRouting 215FRR_ZEBRA_NEXTHOP_IFINDEX = 1 216FRR_ZEBRA_NEXTHOP_IPV4 = 2 217FRR_ZEBRA_NEXTHOP_IPV4_IFINDEX = 3 218FRR_ZEBRA_NEXTHOP_IPV6 = 4 219FRR_ZEBRA_NEXTHOP_IPV6_IFINDEX = 5 220FRR_ZEBRA_NEXTHOP_BLACKHOLE = 6 221 222# Constants in quagga/lib/zclient.h 223 224# Zebra API message flags 225ZAPI_MESSAGE_NEXTHOP = 0x01 226ZAPI_MESSAGE_IFINDEX = 0x02 227ZAPI_MESSAGE_DISTANCE = 0x04 228ZAPI_MESSAGE_METRIC = 0x08 229ZAPI_MESSAGE_MTU = 0x10 230ZAPI_MESSAGE_TAG = 0x20 231 232# Zebra API message flags on FRRouting. 233# Note: Constants for TAG/MTU is inverted from Quagga version. 234FRR_ZAPI_MESSAGE_NEXTHOP = 0x01 235FRR_ZAPI_MESSAGE_IFINDEX = 0x02 236FRR_ZAPI_MESSAGE_DISTANCE = 0x04 237FRR_ZAPI_MESSAGE_METRIC = 0x08 238FRR_ZAPI_MESSAGE_TAG = 0x10 239FRR_ZAPI_MESSAGE_MTU = 0x20 240FRR_ZAPI_MESSAGE_SRCPFX = 0x40 241FRR_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 250INTERFACE_NAMSIZE = 20 251INTERFACE_HWADDR_MAX = 20 252 253# Zebra internal interface status 254ZEBRA_INTERFACE_ACTIVE = 1 << 0 255ZEBRA_INTERFACE_SUB = 1 << 1 256ZEBRA_INTERFACE_LINKDETECTION = 1 << 2 257# Followings are extended on FRRouting 258ZEBRA_INTERFACE_VRF_LOOPBACK = 1 << 3 259 260# Zebra interface connected address flags 261ZEBRA_IFA_SECONDARY = 1 << 0 262ZEBRA_IFA_PEER = 1 << 1 263ZEBRA_IFA_UNNUMBERED = 1 << 2 264 265# Zebra link layer types 266ZEBRA_LLT_UNKNOWN = 0 267ZEBRA_LLT_ETHER = 1 268ZEBRA_LLT_EETHER = 2 269ZEBRA_LLT_AX25 = 3 270ZEBRA_LLT_PRONET = 4 271ZEBRA_LLT_IEEE802 = 5 272ZEBRA_LLT_ARCNET = 6 273ZEBRA_LLT_APPLETLK = 7 274ZEBRA_LLT_DLCI = 8 275ZEBRA_LLT_ATM = 9 276ZEBRA_LLT_METRICOM = 10 277ZEBRA_LLT_IEEE1394 = 11 278ZEBRA_LLT_EUI64 = 12 279ZEBRA_LLT_INFINIBAND = 13 280ZEBRA_LLT_SLIP = 14 281ZEBRA_LLT_CSLIP = 15 282ZEBRA_LLT_SLIP6 = 16 283ZEBRA_LLT_CSLIP6 = 17 284ZEBRA_LLT_RSRVD = 18 285ZEBRA_LLT_ADAPT = 19 286ZEBRA_LLT_ROSE = 20 287ZEBRA_LLT_X25 = 21 288ZEBRA_LLT_PPP = 22 289ZEBRA_LLT_CHDLC = 23 290ZEBRA_LLT_LAPB = 24 291ZEBRA_LLT_RAWHDLC = 25 292ZEBRA_LLT_IPIP = 26 293ZEBRA_LLT_IPIP6 = 27 294ZEBRA_LLT_FRAD = 28 295ZEBRA_LLT_SKIP = 29 296ZEBRA_LLT_LOOPBACK = 30 297ZEBRA_LLT_LOCALTLK = 31 298ZEBRA_LLT_FDDI = 32 299ZEBRA_LLT_SIT = 33 300ZEBRA_LLT_IPDDP = 34 301ZEBRA_LLT_IPGRE = 35 302ZEBRA_LLT_IP6GRE = 36 303ZEBRA_LLT_PIMREG = 37 304ZEBRA_LLT_HIPPI = 38 305ZEBRA_LLT_ECONET = 39 306ZEBRA_LLT_IRDA = 40 307ZEBRA_LLT_FCPP = 41 308ZEBRA_LLT_FCAL = 42 309ZEBRA_LLT_FCPL = 43 310ZEBRA_LLT_FCFABRIC = 44 311ZEBRA_LLT_IEEE802_TR = 45 312ZEBRA_LLT_IEEE80211 = 46 313ZEBRA_LLT_IEEE80211_RADIOTAP = 47 314ZEBRA_LLT_IEEE802154 = 48 315ZEBRA_LLT_IEEE802154_PHY = 49 316 317# Link Parameters Status 318LP_UNSET = 0x0000 319LP_TE = 0x0001 320LP_MAX_BW = 0x0002 321LP_MAX_RSV_BW = 0x0004 322LP_UNRSV_BW = 0x0008 323LP_ADM_GRP = 0x0010 324LP_RMT_AS = 0x0020 325LP_DELAY = 0x0040 326LP_MM_DELAY = 0x0080 327LP_DELAY_VAR = 0x0100 328LP_PKT_LOSS = 0x0200 329LP_RES_BW = 0x0400 330LP_AVA_BW = 0x0800 331LP_USE_BW = 0x1000 332LP_TE_METRIC = 0x2000 333 334# "non-official" architectural constants 335MAX_CLASS_TYPE = 8 336 337# Constants in frr/zebra/zebra_ptm.h 338 339# Interface PTM Enable configuration 340ZEBRA_IF_PTM_ENABLE_OFF = 0 341ZEBRA_IF_PTM_ENABLE_ON = 1 342ZEBRA_IF_PTM_ENABLE_UNSPEC = 2 343 344# PTM status 345ZEBRA_PTM_STATUS_DOWN = 0 346ZEBRA_PTM_STATUS_UP = 1 347ZEBRA_PTM_STATUS_UNKNOWN = 2 348 349# Constants in frr/lib/bfd.h 350 351# BFD status 352BFD_STATUS_UNKNOWN = 1 << 0 353BFD_STATUS_DOWN = 1 << 1 354BFD_STATUS_UP = 1 << 2 355 356# Constants in frr/lib/vrf.h 357 358# VRF name length 359VRF_NAMSIZ = 36 360 361# Constants in frr/lib/mpls.h 362 363# Reserved MPLS label values 364MPLS_V4_EXP_NULL_LABEL = 0 365MPLS_RA_LABEL = 1 366MPLS_V6_EXP_NULL_LABEL = 2 367MPLS_IMP_NULL_LABEL = 3 368MPLS_ENTROPY_LABEL_INDICATOR = 7 369MPLS_GAL_LABEL = 13 370MPLS_OAM_ALERT_LABEL = 14 371MPLS_EXTENSION_LABEL = 15 372MPLS_MIN_RESERVED_LABEL = 0 373MPLS_MAX_RESERVED_LABEL = 15 374MPLS_MIN_UNRESERVED_LABEL = 16 375MPLS_MAX_UNRESERVED_LABEL = 1048575 376 377 378# Utility functions/classes 379 380IPv4Prefix = bgp.IPAddrPrefix 381IPv6Prefix = bgp.IP6AddrPrefix 382 383 384def _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 395def _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 426def _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 447def _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 471def _is_frr_version_ge(compared_version): 472 return CONF['zapi'].frr_version >= compared_version 473 474 475class 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) 601class _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) 655class _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 666def _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 686def _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) 701class 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) 720class 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) 740class 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) 772class 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) 794class 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) 817class 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) 849class 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) 871class 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) 894class 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 907class 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 956class 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 1170class _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 1181zebra = ZebraMessage 1182 1183 1184# Zebra message body classes 1185 1186class _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 1211class _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() 1219class 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) 1237class _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) 1457class 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) 1465class ZebraInterfaceDelete(_ZebraInterface): 1466 """ 1467 Message body class for ZEBRA_INTERFACE_DELETE. 1468 """ 1469 1470 1471@six.add_metaclass(abc.ABCMeta) 1472class _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) 1541class 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) 1549class 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) 1557class 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) 1565class ZebraInterfaceDown(_ZebraInterface): 1566 """ 1567 Message body class for ZEBRA_INTERFACE_DOWN. 1568 """ 1569 1570 1571@six.add_metaclass(abc.ABCMeta) 1572class _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 1923class _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) 1932class 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) 1940class ZebraIPv4RouteDelete(_ZebraIPv4Route): 1941 """ 1942 Message body class for ZEBRA_IPV4_ROUTE_DELETE. 1943 """ 1944 1945 1946class _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) 1955class 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) 1963class 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) 1970class ZebraIPv4RouteIPv6NexthopAdd(_ZebraIPv4Route): 1971 """ 1972 Message body class for FRR_ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD. 1973 """ 1974 1975 1976@six.add_metaclass(abc.ABCMeta) 1977class _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) 2036class 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) 2044class ZebraRedistributeDelete(_ZebraRedistribute): 2045 """ 2046 Message body class for ZEBRA_REDISTRIBUTE_DELETE. 2047 """ 2048 2049 2050@six.add_metaclass(abc.ABCMeta) 2051class _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) 2060class 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) 2068class ZebraRedistributeDefaultDelete(_ZebraRedistribute): 2069 """ 2070 Message body class for ZEBRA_REDISTRIBUTE_DEFAULT_DELETE. 2071 """ 2072 2073 2074@six.add_metaclass(abc.ABCMeta) 2075class _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) 2138class 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) 2147class 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) 2156class _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) 2264class 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) 2273class 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) 2288class 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) 2296class 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) 2304class 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) 2341class 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) 2389class _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) 2456class 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) 2466class 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) 2474class 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 2511class _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) 2545class 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) 2553class 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) 2561class 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 2645class _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) 2689class 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) 2696class 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) 2703class 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) 2779class 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) 2786class 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) 2793class ZebraImportCheckUpdate(ZebraNexthopUpdate): 2794 """ 2795 Message body class for FRR_ZEBRA_IMPORT_CHECK_UPDATE. 2796 """ 2797 2798 2799class _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) 2941class 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) 2948class 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) 3073class 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) 3080class ZebraBfdDestinationReply(_ZebraMessageBody): 3081 """ 3082 Message body class for FRR_ZEBRA_BFD_DEST_REPLAY. 3083 """ 3084 3085 3086class _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) 3094class 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) 3101class ZebraRedistributeIPv4Delete(_ZebraRedistributeIPv4): 3102 """ 3103 Message body class for FRR_ZEBRA_IPV4_ROUTE_DELETE. 3104 """ 3105 3106 3107class _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) 3115class 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) 3122class ZebraRedistributeIPv6Delete(_ZebraRedistributeIPv6): 3123 """ 3124 Message body class for FRR_ZEBRA_REDISTRIBUTE_IPV6_DEL. 3125 """ 3126 3127 3128class _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) 3156class ZebraVrfAdd(_ZebraVrf): 3157 """ 3158 Message body class for FRR_ZEBRA_VRF_ADD. 3159 """ 3160 3161 3162@_FrrZebraMessageBody.register_type(FRR_ZEBRA_VRF_DELETE) 3163class ZebraVrfDelete(_ZebraVrf): 3164 """ 3165 Message body class for FRR_ZEBRA_VRF_DELETE. 3166 """ 3167 3168 3169@_FrrZebraMessageBody.register_type(FRR_ZEBRA_INTERFACE_VRF_UPDATE) 3170class 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 3199class _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) 3227class ZebraBfdClientRegister(_ZebraBfdClient): 3228 """ 3229 Message body class for FRR_ZEBRA_BFD_CLIENT_REGISTER. 3230 """ 3231 3232 3233class _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) 3264class 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) 3271class ZebraInterfaceDisableRadv(_ZebraInterfaceRadv): 3272 """ 3273 Message body class for FRR_ZEBRA_INTERFACE_DISABLE_RADV. 3274 """ 3275 3276 3277class _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) 3426class 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) 3433class ZebraMplsLabelsDelete(_ZebraMplsLabels): 3434 """ 3435 Message body class for FRR_ZEBRA_MPLS_LABELS_DELETE. 3436 """ 3437 3438 3439class _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) 3447class 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) 3454class ZebraIPv4NexthopDelete(_ZebraIPv4Nexthop): 3455 """ 3456 Message body class for FRR_ZEBRA_IPV4_NEXTHOP_DELETE. 3457 """ 3458 3459 3460class _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) 3468class 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) 3475class ZebraIPv6NexthopDelete(_ZebraIPv6Nexthop): 3476 """ 3477 Message body class for FRR_ZEBRA_IPV6_NEXTHOP_DELETE. 3478 """ 3479