2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2002-12-13 21:15:29 +01:00
|
|
|
/*
|
|
|
|
* Prefix related functions.
|
|
|
|
* Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
2022-07-01 22:26:24 +02:00
|
|
|
#include "command.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "prefix.h"
|
2020-03-29 11:09:14 +02:00
|
|
|
#include "ipaddr.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "vty.h"
|
|
|
|
#include "sockunion.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "log.h"
|
2017-08-03 13:37:38 +02:00
|
|
|
#include "jhash.h"
|
2018-06-18 15:13:37 +02:00
|
|
|
#include "lib_errors.h"
|
2019-05-14 16:28:31 +02:00
|
|
|
#include "printfrr.h"
|
2020-05-09 01:35:09 +02:00
|
|
|
#include "vxlan.h"
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2015-05-29 05:48:31 +02:00
|
|
|
DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix");
|
2019-02-07 15:35:01 +01:00
|
|
|
DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec");
|
2015-05-29 05:48:31 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Maskbit. */
|
2018-03-27 21:13:34 +02:00
|
|
|
static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
|
|
|
|
0xf8, 0xfc, 0xfe, 0xff};
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Number of bits in prefix type. */
|
|
|
|
#ifndef PNBBY
|
|
|
|
#define PNBBY 8
|
|
|
|
#endif /* PNBBY */
|
|
|
|
|
|
|
|
#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff)
|
|
|
|
|
2019-08-22 14:36:59 +02:00
|
|
|
int is_zero_mac(const struct ethaddr *mac)
|
2017-07-12 23:27:24 +02:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < ETH_ALEN; i++) {
|
|
|
|
if (mac->octet[i])
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-02-10 20:38:27 +01:00
|
|
|
bool is_bcast_mac(const struct ethaddr *mac)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < ETH_ALEN; i++)
|
|
|
|
if (mac->octet[i] != 0xFF)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_mcast_mac(const struct ethaddr *mac)
|
|
|
|
{
|
|
|
|
if ((mac->octet[0] & 0x01) == 0x01)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-22 19:59:01 +02:00
|
|
|
unsigned int prefix_bit(const uint8_t *prefix, const uint16_t bit_index)
|
2011-04-08 13:44:43 +02:00
|
|
|
{
|
2020-06-22 19:59:01 +02:00
|
|
|
unsigned int offset = bit_index / 8;
|
|
|
|
unsigned int shift = 7 - (bit_index % 8);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2011-04-08 13:44:43 +02:00
|
|
|
return (prefix[offset] >> shift) & 1;
|
|
|
|
}
|
|
|
|
|
2015-11-12 14:24:22 +01:00
|
|
|
int str2family(const char *string)
|
|
|
|
{
|
|
|
|
if (!strcmp("ipv4", string))
|
|
|
|
return AF_INET;
|
|
|
|
else if (!strcmp("ipv6", string))
|
|
|
|
return AF_INET6;
|
2016-04-19 22:08:59 +02:00
|
|
|
else if (!strcmp("ethernet", string))
|
|
|
|
return AF_ETHERNET;
|
2017-08-08 16:16:12 +02:00
|
|
|
else if (!strcmp("evpn", string))
|
|
|
|
return AF_EVPN;
|
2016-04-19 22:08:59 +02:00
|
|
|
return -1;
|
2015-11-12 14:24:22 +01:00
|
|
|
}
|
|
|
|
|
2018-03-28 18:56:45 +02:00
|
|
|
const char *family2str(int family)
|
|
|
|
{
|
|
|
|
switch (family) {
|
|
|
|
case AF_INET:
|
|
|
|
return "IPv4";
|
|
|
|
case AF_INET6:
|
|
|
|
return "IPv6";
|
|
|
|
case AF_ETHERNET:
|
|
|
|
return "Ethernet";
|
|
|
|
case AF_EVPN:
|
|
|
|
return "Evpn";
|
|
|
|
}
|
|
|
|
return "?";
|
|
|
|
}
|
|
|
|
|
2021-10-05 23:33:14 +02:00
|
|
|
/* Address Family Identifier to Address Family converter. */
|
2010-07-22 19:20:55 +02:00
|
|
|
int afi2family(afi_t afi)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
if (afi == AFI_IP)
|
|
|
|
return AF_INET;
|
|
|
|
else if (afi == AFI_IP6)
|
|
|
|
return AF_INET6;
|
2016-08-02 20:51:35 +02:00
|
|
|
else if (afi == AFI_L2VPN)
|
2016-04-19 22:08:59 +02:00
|
|
|
return AF_ETHERNET;
|
2017-08-08 16:16:12 +02:00
|
|
|
/* NOTE: EVPN code should NOT use this interface. */
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
afi_t family2afi(int family)
|
|
|
|
{
|
|
|
|
if (family == AF_INET)
|
|
|
|
return AFI_IP;
|
|
|
|
else if (family == AF_INET6)
|
|
|
|
return AFI_IP6;
|
2017-08-08 16:16:12 +02:00
|
|
|
else if (family == AF_ETHERNET || family == AF_EVPN)
|
2016-08-02 20:51:35 +02:00
|
|
|
return AFI_L2VPN;
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-02-23 20:22:33 +01:00
|
|
|
const char *afi2str_lower(afi_t afi)
|
|
|
|
{
|
|
|
|
switch (afi) {
|
|
|
|
case AFI_IP:
|
|
|
|
return "ipv4";
|
|
|
|
case AFI_IP6:
|
|
|
|
return "ipv6";
|
|
|
|
case AFI_L2VPN:
|
|
|
|
return "l2vpn";
|
2022-12-27 15:13:18 +01:00
|
|
|
case AFI_LINKSTATE:
|
|
|
|
return "link-state";
|
2023-02-23 20:22:33 +01:00
|
|
|
case AFI_MAX:
|
|
|
|
case AFI_UNSPEC:
|
|
|
|
return "bad-value";
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!"Reached end of function we should never reach");
|
|
|
|
}
|
|
|
|
|
2016-04-19 22:08:59 +02:00
|
|
|
const char *afi2str(afi_t afi)
|
|
|
|
{
|
|
|
|
switch (afi) {
|
|
|
|
case AFI_IP:
|
|
|
|
return "IPv4";
|
|
|
|
case AFI_IP6:
|
|
|
|
return "IPv6";
|
2016-12-05 14:11:07 +01:00
|
|
|
case AFI_L2VPN:
|
|
|
|
return "l2vpn";
|
2022-12-27 15:13:18 +01:00
|
|
|
case AFI_LINKSTATE:
|
|
|
|
return "link-state";
|
bgpd: add L3/L2VPN Virtual Network Control feature
This feature adds an L3 & L2 VPN application that makes use of the VPN
and Encap SAFIs. This code is currently used to support IETF NVO3 style
operation. In NVO3 terminology it provides the Network Virtualization
Authority (NVA) and the ability to import/export IP prefixes and MAC
addresses from Network Virtualization Edges (NVEs). The code supports
per-NVE tables.
The NVE-NVA protocol used to communicate routing and Ethernet / Layer 2
(L2) forwarding information between NVAs and NVEs is referred to as the
Remote Forwarder Protocol (RFP). OpenFlow is an example RFP. For
general background on NVO3 and RFP concepts see [1]. For information on
Openflow see [2].
RFPs are integrated with BGP via the RF API contained in the new "rfapi"
BGP sub-directory. Currently, only a simple example RFP is included in
Quagga. Developers may use this example as a starting point to integrate
Quagga with an RFP of their choosing, e.g., OpenFlow. The RFAPI code
also supports the ability import/export of routing information between
VNC and customer edge routers (CEs) operating within a virtual
network. Import/export may take place between BGP views or to the
default zebera VRF.
BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VPN
information between NVAs. BGP based IP VPN support is defined in
RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs), and RFC4659,
BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN . Use
of both the Encapsulation Subsequent Address Family Identifier (SAFI)
and the Tunnel Encapsulation Attribute, RFC5512, The BGP Encapsulation
Subsequent Address Family Identifier (SAFI) and the BGP Tunnel
Encapsulation Attribute, are supported. MAC address distribution does
not follow any standard BGB encoding, although it was inspired by the
early IETF EVPN concepts.
The feature is conditionally compiled and disabled by default.
Use the --enable-bgp-vnc configure option to enable.
The majority of this code was authored by G. Paul Ziemba
<paulz@labn.net>.
[1] http://tools.ietf.org/html/draft-ietf-nvo3-nve-nva-cp-req
[2] https://www.opennetworking.org/sdn-resources/technical-library
Now includes changes needed to merge with cmaster-next.
2016-05-07 20:18:56 +02:00
|
|
|
case AFI_MAX:
|
2023-01-30 16:06:29 +01:00
|
|
|
case AFI_UNSPEC:
|
bgpd: add L3/L2VPN Virtual Network Control feature
This feature adds an L3 & L2 VPN application that makes use of the VPN
and Encap SAFIs. This code is currently used to support IETF NVO3 style
operation. In NVO3 terminology it provides the Network Virtualization
Authority (NVA) and the ability to import/export IP prefixes and MAC
addresses from Network Virtualization Edges (NVEs). The code supports
per-NVE tables.
The NVE-NVA protocol used to communicate routing and Ethernet / Layer 2
(L2) forwarding information between NVAs and NVEs is referred to as the
Remote Forwarder Protocol (RFP). OpenFlow is an example RFP. For
general background on NVO3 and RFP concepts see [1]. For information on
Openflow see [2].
RFPs are integrated with BGP via the RF API contained in the new "rfapi"
BGP sub-directory. Currently, only a simple example RFP is included in
Quagga. Developers may use this example as a starting point to integrate
Quagga with an RFP of their choosing, e.g., OpenFlow. The RFAPI code
also supports the ability import/export of routing information between
VNC and customer edge routers (CEs) operating within a virtual
network. Import/export may take place between BGP views or to the
default zebera VRF.
BGP, with IP VPNs and Tunnel Encapsulation, is used to distribute VPN
information between NVAs. BGP based IP VPN support is defined in
RFC4364, BGP/MPLS IP Virtual Private Networks (VPNs), and RFC4659,
BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN . Use
of both the Encapsulation Subsequent Address Family Identifier (SAFI)
and the Tunnel Encapsulation Attribute, RFC5512, The BGP Encapsulation
Subsequent Address Family Identifier (SAFI) and the BGP Tunnel
Encapsulation Attribute, are supported. MAC address distribution does
not follow any standard BGB encoding, although it was inspired by the
early IETF EVPN concepts.
The feature is conditionally compiled and disabled by default.
Use the --enable-bgp-vnc configure option to enable.
The majority of this code was authored by G. Paul Ziemba
<paulz@labn.net>.
[1] http://tools.ietf.org/html/draft-ietf-nvo3-nve-nva-cp-req
[2] https://www.opennetworking.org/sdn-resources/technical-library
Now includes changes needed to merge with cmaster-next.
2016-05-07 20:18:56 +02:00
|
|
|
return "bad-value";
|
2016-04-19 22:08:59 +02:00
|
|
|
}
|
2023-01-30 16:06:29 +01:00
|
|
|
|
|
|
|
assert(!"Reached end of function we should never reach");
|
2016-04-19 22:08:59 +02:00
|
|
|
}
|
|
|
|
|
2016-01-12 19:41:50 +01:00
|
|
|
const char *safi2str(safi_t safi)
|
|
|
|
{
|
|
|
|
switch (safi) {
|
|
|
|
case SAFI_UNICAST:
|
|
|
|
return "unicast";
|
|
|
|
case SAFI_MULTICAST:
|
|
|
|
return "multicast";
|
|
|
|
case SAFI_MPLS_VPN:
|
|
|
|
return "vpn";
|
2017-05-12 14:21:34 +02:00
|
|
|
case SAFI_ENCAP:
|
|
|
|
return "encap";
|
2016-12-05 14:11:07 +01:00
|
|
|
case SAFI_EVPN:
|
|
|
|
return "evpn";
|
2017-05-12 14:21:34 +02:00
|
|
|
case SAFI_LABELED_UNICAST:
|
|
|
|
return "labeled-unicast";
|
2017-01-23 03:45:30 +01:00
|
|
|
case SAFI_FLOWSPEC:
|
|
|
|
return "flowspec";
|
2022-12-27 15:13:18 +01:00
|
|
|
case SAFI_LINKSTATE:
|
|
|
|
return "link-state";
|
|
|
|
case SAFI_LINKSTATE_VPN:
|
|
|
|
return "link-state-vpn";
|
2023-01-30 16:06:29 +01:00
|
|
|
case SAFI_UNSPEC:
|
|
|
|
case SAFI_MAX:
|
2017-08-01 02:06:40 +02:00
|
|
|
return "unknown";
|
2016-01-12 19:41:50 +01:00
|
|
|
}
|
2023-01-30 16:06:29 +01:00
|
|
|
|
|
|
|
assert(!"Reached end of function we should never reach");
|
2016-01-12 19:41:50 +01:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If n includes p prefix then return 1 else return 0. */
|
2022-04-08 18:17:38 +02:00
|
|
|
int prefix_match(union prefixconstptr unet, union prefixconstptr upfx)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2022-04-08 18:17:38 +02:00
|
|
|
const struct prefix *n = unet.p;
|
|
|
|
const struct prefix *p = upfx.p;
|
2002-12-13 21:15:29 +01:00
|
|
|
int offset;
|
|
|
|
int shift;
|
2018-03-27 21:13:34 +02:00
|
|
|
const uint8_t *np, *pp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If n's prefix is longer than p's one return 0. */
|
|
|
|
if (n->prefixlen > p->prefixlen)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-01-10 19:13:27 +01:00
|
|
|
if (n->family == AF_FLOWSPEC) {
|
|
|
|
/* prefixlen is unused. look at fs prefix len */
|
2019-10-15 15:01:39 +02:00
|
|
|
if (n->u.prefix_flowspec.family !=
|
|
|
|
p->u.prefix_flowspec.family)
|
|
|
|
return 0;
|
|
|
|
|
2018-01-10 19:13:27 +01:00
|
|
|
if (n->u.prefix_flowspec.prefixlen >
|
|
|
|
p->u.prefix_flowspec.prefixlen)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Set both prefix's head pointer. */
|
|
|
|
np = (const uint8_t *)&n->u.prefix_flowspec.ptr;
|
|
|
|
pp = (const uint8_t *)&p->u.prefix_flowspec.ptr;
|
|
|
|
|
|
|
|
offset = n->u.prefix_flowspec.prefixlen;
|
|
|
|
|
|
|
|
while (offset--)
|
|
|
|
if (np[offset] != pp[offset])
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-01-24 22:41:02 +01:00
|
|
|
/* Set both prefix's head pointer. */
|
2018-06-12 19:16:39 +02:00
|
|
|
np = n->u.val;
|
|
|
|
pp = p->u.val;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
offset = n->prefixlen / PNBBY;
|
|
|
|
shift = n->prefixlen % PNBBY;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (shift)
|
|
|
|
if (maskbit[shift] & (np[offset] ^ pp[offset]))
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-28 20:53:27 +02:00
|
|
|
while (offset--)
|
|
|
|
if (np[offset] != pp[offset])
|
|
|
|
return 0;
|
|
|
|
return 1;
|
2019-09-11 09:01:39 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* n is a type5 evpn prefix. This function tries to see if there is an
|
|
|
|
* ip-prefix within n which matches prefix p
|
|
|
|
* If n includes p prefix then return 1 else return 0.
|
|
|
|
*/
|
|
|
|
int evpn_type5_prefix_match(const struct prefix *n, const struct prefix *p)
|
|
|
|
{
|
|
|
|
int offset;
|
|
|
|
int shift;
|
|
|
|
int prefixlen;
|
|
|
|
const uint8_t *np, *pp;
|
|
|
|
struct prefix_evpn *evp;
|
|
|
|
|
|
|
|
if (n->family != AF_EVPN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
evp = (struct prefix_evpn *)n;
|
|
|
|
pp = p->u.val;
|
|
|
|
|
|
|
|
if ((evp->prefix.route_type != 5) ||
|
|
|
|
(p->family == AF_INET6 && !is_evpn_prefix_ipaddr_v6(evp)) ||
|
|
|
|
(p->family == AF_INET && !is_evpn_prefix_ipaddr_v4(evp)) ||
|
|
|
|
(is_evpn_prefix_ipaddr_none(evp)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
prefixlen = evp->prefix.prefix_addr.ip_prefix_length;
|
|
|
|
np = &evp->prefix.prefix_addr.ip.ip.addr;
|
|
|
|
|
|
|
|
/* If n's prefix is longer than p's one return 0. */
|
|
|
|
if (prefixlen > p->prefixlen)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
offset = prefixlen / PNBBY;
|
|
|
|
shift = prefixlen % PNBBY;
|
|
|
|
|
|
|
|
if (shift)
|
|
|
|
if (maskbit[shift] & (np[offset] ^ pp[offset]))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
while (offset--)
|
|
|
|
if (np[offset] != pp[offset])
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
|
2017-06-28 20:53:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If n includes p then return 1 else return 0. Prefix mask is not considered */
|
2022-04-08 18:17:38 +02:00
|
|
|
int prefix_match_network_statement(union prefixconstptr unet,
|
|
|
|
union prefixconstptr upfx)
|
2017-06-28 20:53:27 +02:00
|
|
|
{
|
2022-04-08 18:17:38 +02:00
|
|
|
const struct prefix *n = unet.p;
|
|
|
|
const struct prefix *p = upfx.p;
|
2017-06-28 20:53:27 +02:00
|
|
|
int offset;
|
|
|
|
int shift;
|
2018-03-27 21:13:34 +02:00
|
|
|
const uint8_t *np, *pp;
|
2017-06-28 20:53:27 +02:00
|
|
|
|
|
|
|
/* Set both prefix's head pointer. */
|
2018-06-12 19:16:39 +02:00
|
|
|
np = n->u.val;
|
|
|
|
pp = p->u.val;
|
2017-06-28 20:53:27 +02:00
|
|
|
|
|
|
|
offset = n->prefixlen / PNBBY;
|
|
|
|
shift = n->prefixlen % PNBBY;
|
|
|
|
|
|
|
|
if (shift)
|
|
|
|
if (maskbit[shift] & (np[offset] ^ pp[offset]))
|
|
|
|
return 0;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
while (offset--)
|
|
|
|
if (np[offset] != pp[offset])
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-07-29 15:49:49 +02:00
|
|
|
#ifdef __clang_analyzer__
|
|
|
|
#undef prefix_copy /* cf. prefix.h */
|
|
|
|
#endif
|
|
|
|
|
2019-07-28 09:26:21 +02:00
|
|
|
void prefix_copy(union prefixptr udest, union prefixconstptr usrc)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-07-28 09:26:21 +02:00
|
|
|
struct prefix *dest = udest.p;
|
|
|
|
const struct prefix *src = usrc.p;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
dest->family = src->family;
|
|
|
|
dest->prefixlen = src->prefixlen;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (src->family == AF_INET)
|
|
|
|
dest->u.prefix4 = src->u.prefix4;
|
|
|
|
else if (src->family == AF_INET6)
|
|
|
|
dest->u.prefix6 = src->u.prefix6;
|
2016-08-02 20:51:35 +02:00
|
|
|
else if (src->family == AF_ETHERNET) {
|
2017-08-08 16:16:12 +02:00
|
|
|
memcpy(&dest->u.prefix_eth, &src->u.prefix_eth,
|
|
|
|
sizeof(struct ethaddr));
|
|
|
|
} else if (src->family == AF_EVPN) {
|
2016-08-02 20:51:35 +02:00
|
|
|
memcpy(&dest->u.prefix_evpn, &src->u.prefix_evpn,
|
|
|
|
sizeof(struct evpn_addr));
|
2002-12-13 21:15:29 +01:00
|
|
|
} else if (src->family == AF_UNSPEC) {
|
|
|
|
dest->u.lp.id = src->u.lp.id;
|
|
|
|
dest->u.lp.adv_router = src->u.lp.adv_router;
|
2018-01-10 19:13:27 +01:00
|
|
|
} else if (src->family == AF_FLOWSPEC) {
|
|
|
|
void *temp;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
len = src->u.prefix_flowspec.prefixlen;
|
|
|
|
dest->u.prefix_flowspec.prefixlen =
|
|
|
|
src->u.prefix_flowspec.prefixlen;
|
2019-10-15 15:01:39 +02:00
|
|
|
dest->u.prefix_flowspec.family =
|
|
|
|
src->u.prefix_flowspec.family;
|
2018-01-10 19:13:27 +01:00
|
|
|
dest->family = src->family;
|
|
|
|
temp = XCALLOC(MTYPE_PREFIX_FLOWSPEC, len);
|
|
|
|
dest->u.prefix_flowspec.ptr = (uintptr_t)temp;
|
|
|
|
memcpy((void *)dest->u.prefix_flowspec.ptr,
|
|
|
|
(void *)src->u.prefix_flowspec.ptr, len);
|
2002-12-13 21:15:29 +01:00
|
|
|
} else {
|
2018-09-13 21:34:28 +02:00
|
|
|
flog_err(EC_LIB_DEVELOPMENT,
|
2018-09-13 21:38:57 +02:00
|
|
|
"prefix_copy(): Unknown address family %d",
|
|
|
|
src->family);
|
2002-12-13 21:15:29 +01:00
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-30 15:42:06 +02:00
|
|
|
bool evpn_addr_same(const struct evpn_addr *e1, const struct evpn_addr *e2)
|
|
|
|
{
|
|
|
|
if (e1->route_type != e2->route_type)
|
|
|
|
return false;
|
|
|
|
if (e1->route_type == BGP_EVPN_AD_ROUTE)
|
|
|
|
return (!memcmp(&e1->ead_addr.esi.val,
|
|
|
|
&e2->ead_addr.esi.val, ESI_BYTES) &&
|
|
|
|
e1->ead_addr.eth_tag == e2->ead_addr.eth_tag &&
|
|
|
|
!ipaddr_cmp(&e1->ead_addr.ip, &e2->ead_addr.ip));
|
|
|
|
if (e1->route_type == BGP_EVPN_MAC_IP_ROUTE)
|
|
|
|
return (e1->macip_addr.eth_tag == e2->macip_addr.eth_tag &&
|
|
|
|
e1->macip_addr.ip_prefix_length
|
|
|
|
== e2->macip_addr.ip_prefix_length &&
|
|
|
|
!memcmp(&e1->macip_addr.mac,
|
|
|
|
&e2->macip_addr.mac, ETH_ALEN) &&
|
|
|
|
!ipaddr_cmp(&e1->macip_addr.ip, &e2->macip_addr.ip));
|
|
|
|
if (e1->route_type == BGP_EVPN_IMET_ROUTE)
|
|
|
|
return (e1->imet_addr.eth_tag == e2->imet_addr.eth_tag &&
|
|
|
|
e1->imet_addr.ip_prefix_length
|
|
|
|
== e2->imet_addr.ip_prefix_length &&
|
|
|
|
!ipaddr_cmp(&e1->imet_addr.ip, &e2->imet_addr.ip));
|
|
|
|
if (e1->route_type == BGP_EVPN_ES_ROUTE)
|
|
|
|
return (!memcmp(&e1->es_addr.esi.val,
|
|
|
|
&e2->es_addr.esi.val, ESI_BYTES) &&
|
|
|
|
e1->es_addr.ip_prefix_length
|
|
|
|
== e2->es_addr.ip_prefix_length &&
|
|
|
|
!ipaddr_cmp(&e1->es_addr.ip, &e2->es_addr.ip));
|
|
|
|
if (e1->route_type == BGP_EVPN_IP_PREFIX_ROUTE)
|
|
|
|
return (e1->prefix_addr.eth_tag == e2->prefix_addr.eth_tag &&
|
|
|
|
e1->prefix_addr.ip_prefix_length
|
|
|
|
== e2->prefix_addr.ip_prefix_length &&
|
|
|
|
!ipaddr_cmp(&e1->prefix_addr.ip, &e2->prefix_addr.ip));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-01-13 15:55:40 +01:00
|
|
|
/*
|
|
|
|
* Return 1 if the address/netmask contained in the prefix structure
|
|
|
|
* is the same, and else return 0. For this routine, 'same' requires
|
|
|
|
* that not only the prefix length and the network part be the same,
|
|
|
|
* but also the host part. Thus, 10.0.0.1/8 and 10.0.0.2/8 are not
|
|
|
|
* the same. Note that this routine has the same return value sense
|
|
|
|
* as '==' (which is different from prefix_cmp).
|
|
|
|
*/
|
2019-07-28 09:26:21 +02:00
|
|
|
int prefix_same(union prefixconstptr up1, union prefixconstptr up2)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-07-28 09:26:21 +02:00
|
|
|
const struct prefix *p1 = up1.p;
|
|
|
|
const struct prefix *p2 = up2.p;
|
|
|
|
|
2015-05-20 03:04:16 +02:00
|
|
|
if ((p1 && !p2) || (!p1 && p2))
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-20 03:04:16 +02:00
|
|
|
if (!p1 && !p2)
|
|
|
|
return 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (p1->family == p2->family && p1->prefixlen == p2->prefixlen) {
|
|
|
|
if (p1->family == AF_INET)
|
2017-08-09 13:57:49 +02:00
|
|
|
if (IPV4_ADDR_SAME(&p1->u.prefix4, &p2->u.prefix4))
|
2002-12-13 21:15:29 +01:00
|
|
|
return 1;
|
|
|
|
if (p1->family == AF_INET6)
|
2011-12-18 12:40:17 +01:00
|
|
|
if (IPV6_ADDR_SAME(&p1->u.prefix6.s6_addr,
|
|
|
|
&p2->u.prefix6.s6_addr))
|
2002-12-13 21:15:29 +01:00
|
|
|
return 1;
|
2016-08-02 20:51:35 +02:00
|
|
|
if (p1->family == AF_ETHERNET)
|
2017-08-08 16:16:12 +02:00
|
|
|
if (!memcmp(&p1->u.prefix_eth, &p2->u.prefix_eth,
|
|
|
|
sizeof(struct ethaddr)))
|
|
|
|
return 1;
|
|
|
|
if (p1->family == AF_EVPN)
|
2022-05-30 15:42:06 +02:00
|
|
|
if (evpn_addr_same(&p1->u.prefix_evpn, &p2->u.prefix_evpn))
|
2016-08-02 20:51:35 +02:00
|
|
|
return 1;
|
2018-01-10 19:13:27 +01:00
|
|
|
if (p1->family == AF_FLOWSPEC) {
|
2019-10-15 15:01:39 +02:00
|
|
|
if (p1->u.prefix_flowspec.family !=
|
|
|
|
p2->u.prefix_flowspec.family)
|
|
|
|
return 0;
|
2018-01-10 19:13:27 +01:00
|
|
|
if (p1->u.prefix_flowspec.prefixlen !=
|
|
|
|
p2->u.prefix_flowspec.prefixlen)
|
|
|
|
return 0;
|
|
|
|
if (!memcmp(&p1->u.prefix_flowspec.ptr,
|
|
|
|
&p2->u.prefix_flowspec.ptr,
|
|
|
|
p2->u.prefix_flowspec.prefixlen))
|
|
|
|
return 1;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-01-13 15:55:40 +01:00
|
|
|
/*
|
2019-07-28 09:24:00 +02:00
|
|
|
* Return -1/0/1 comparing the prefixes in a way that gives a full/linear
|
|
|
|
* order.
|
|
|
|
*
|
|
|
|
* Network prefixes are considered the same if the prefix lengths are equal
|
|
|
|
* and the network parts are the same. Host bits (which are considered masked
|
2004-01-13 15:55:40 +01:00
|
|
|
* by the prefix length) are not significant. Thus, 10.0.0.1/8 and
|
|
|
|
* 10.0.0.2/8 are considered equivalent by this routine. Note that
|
|
|
|
* this routine has the same return sense as strcmp (which is different
|
|
|
|
* from prefix_same).
|
|
|
|
*/
|
2019-07-28 09:26:21 +02:00
|
|
|
int prefix_cmp(union prefixconstptr up1, union prefixconstptr up2)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-07-28 09:26:21 +02:00
|
|
|
const struct prefix *p1 = up1.p;
|
|
|
|
const struct prefix *p2 = up2.p;
|
2002-12-13 21:15:29 +01:00
|
|
|
int offset;
|
|
|
|
int shift;
|
2019-07-28 09:24:00 +02:00
|
|
|
int i;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Set both prefix's head pointer. */
|
2018-01-10 19:13:27 +01:00
|
|
|
const uint8_t *pp1;
|
|
|
|
const uint8_t *pp2;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2018-01-10 19:13:27 +01:00
|
|
|
if (p1->family != p2->family)
|
2019-07-28 09:24:00 +02:00
|
|
|
return numcmp(p1->family, p2->family);
|
2018-01-10 19:13:27 +01:00
|
|
|
if (p1->family == AF_FLOWSPEC) {
|
|
|
|
pp1 = (const uint8_t *)p1->u.prefix_flowspec.ptr;
|
|
|
|
pp2 = (const uint8_t *)p2->u.prefix_flowspec.ptr;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-10-15 15:01:39 +02:00
|
|
|
if (p1->u.prefix_flowspec.family !=
|
|
|
|
p2->u.prefix_flowspec.family)
|
|
|
|
return 1;
|
|
|
|
|
2018-01-10 19:13:27 +01:00
|
|
|
if (p1->u.prefix_flowspec.prefixlen !=
|
|
|
|
p2->u.prefix_flowspec.prefixlen)
|
2019-07-28 09:24:00 +02:00
|
|
|
return numcmp(p1->u.prefix_flowspec.prefixlen,
|
|
|
|
p2->u.prefix_flowspec.prefixlen);
|
2018-01-10 19:13:27 +01:00
|
|
|
|
|
|
|
offset = p1->u.prefix_flowspec.prefixlen;
|
|
|
|
while (offset--)
|
|
|
|
if (pp1[offset] != pp2[offset])
|
2019-07-28 09:24:00 +02:00
|
|
|
return numcmp(pp1[offset], pp2[offset]);
|
2018-01-10 19:13:27 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2018-06-12 19:16:39 +02:00
|
|
|
pp1 = p1->u.val;
|
|
|
|
pp2 = p2->u.val;
|
2018-01-10 19:13:27 +01:00
|
|
|
|
|
|
|
if (p1->prefixlen != p2->prefixlen)
|
2019-07-28 09:24:00 +02:00
|
|
|
return numcmp(p1->prefixlen, p2->prefixlen);
|
2011-10-24 16:45:05 +02:00
|
|
|
offset = p1->prefixlen / PNBBY;
|
|
|
|
shift = p1->prefixlen % PNBBY;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-07-28 09:24:00 +02:00
|
|
|
i = memcmp(pp1, pp2, offset);
|
|
|
|
if (i)
|
|
|
|
return i;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-10-10 14:52:54 +02:00
|
|
|
/*
|
|
|
|
* At this point offset was the same, if we have shift
|
|
|
|
* that means we still have data to compare, if shift is
|
|
|
|
* 0 then we are at the end of the data structure
|
|
|
|
* and should just return, as that we will be accessing
|
|
|
|
* memory beyond the end of the party zone
|
|
|
|
*/
|
|
|
|
if (shift)
|
|
|
|
return numcmp(pp1[offset] & maskbit[shift],
|
|
|
|
pp2[offset] & maskbit[shift]);
|
|
|
|
|
|
|
|
return 0;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2010-02-02 20:16:35 +01:00
|
|
|
/*
|
|
|
|
* Count the number of common bits in 2 prefixes. The prefix length is
|
|
|
|
* ignored for this function; the whole prefix is compared. If the prefix
|
|
|
|
* address families don't match, return -1; otherwise the return value is
|
|
|
|
* in range 0 ... maximum prefix length for the address family.
|
|
|
|
*/
|
2022-04-08 18:17:38 +02:00
|
|
|
int prefix_common_bits(union prefixconstptr ua, union prefixconstptr ub)
|
2010-02-02 20:16:35 +01:00
|
|
|
{
|
2022-04-08 18:17:38 +02:00
|
|
|
const struct prefix *p1 = ua.p;
|
|
|
|
const struct prefix *p2 = ub.p;
|
2010-02-02 20:16:35 +01:00
|
|
|
int pos, bit;
|
|
|
|
int length = 0;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t xor ;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2010-02-02 20:16:35 +01:00
|
|
|
/* Set both prefix's head pointer. */
|
2018-06-12 19:16:39 +02:00
|
|
|
const uint8_t *pp1 = p1->u.val;
|
|
|
|
const uint8_t *pp2 = p2->u.val;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2010-02-02 20:16:35 +01:00
|
|
|
if (p1->family == AF_INET)
|
|
|
|
length = IPV4_MAX_BYTELEN;
|
|
|
|
if (p1->family == AF_INET6)
|
|
|
|
length = IPV6_MAX_BYTELEN;
|
2016-08-02 20:51:35 +02:00
|
|
|
if (p1->family == AF_ETHERNET)
|
2017-08-08 16:16:12 +02:00
|
|
|
length = ETH_ALEN;
|
|
|
|
if (p1->family == AF_EVPN)
|
2016-08-02 20:51:35 +02:00
|
|
|
length = 8 * sizeof(struct evpn_addr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2010-02-02 20:16:35 +01:00
|
|
|
if (p1->family != p2->family || !length)
|
|
|
|
return -1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2010-02-02 20:16:35 +01:00
|
|
|
for (pos = 0; pos < length; pos++)
|
|
|
|
if (pp1[pos] != pp2[pos])
|
|
|
|
break;
|
|
|
|
if (pos == length)
|
|
|
|
return pos * 8;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2010-02-02 20:16:35 +01:00
|
|
|
xor = pp1[pos] ^ pp2[pos];
|
|
|
|
for (bit = 0; bit < 8; bit++)
|
|
|
|
if (xor&(1 << (7 - bit)))
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2010-02-02 20:16:35 +01:00
|
|
|
return pos * 8 + bit;
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Return prefix family type string. */
|
2022-04-08 18:17:38 +02:00
|
|
|
const char *prefix_family_str(union prefixconstptr pu)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2022-04-08 18:17:38 +02:00
|
|
|
const struct prefix *p = pu.p;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (p->family == AF_INET)
|
|
|
|
return "inet";
|
|
|
|
if (p->family == AF_INET6)
|
|
|
|
return "inet6";
|
2016-04-19 22:08:59 +02:00
|
|
|
if (p->family == AF_ETHERNET)
|
|
|
|
return "ether";
|
2017-08-08 16:16:12 +02:00
|
|
|
if (p->family == AF_EVPN)
|
|
|
|
return "evpn";
|
2002-12-13 21:15:29 +01:00
|
|
|
return "unspec";
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate new prefix_ipv4 structure. */
|
2019-01-24 10:12:36 +01:00
|
|
|
struct prefix_ipv4 *prefix_ipv4_new(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct prefix_ipv4 *p;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-07-26 21:55:31 +02:00
|
|
|
/* Call prefix_new to allocate a full-size struct prefix to avoid
|
|
|
|
problems
|
|
|
|
where the struct prefix_ipv4 is cast to struct prefix and unallocated
|
|
|
|
bytes were being referenced (e.g. in structure assignments). */
|
|
|
|
p = (struct prefix_ipv4 *)prefix_new();
|
2002-12-13 21:15:29 +01:00
|
|
|
p->family = AF_INET;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free prefix_ipv4 structure. */
|
2019-10-30 01:05:27 +01:00
|
|
|
void prefix_ipv4_free(struct prefix_ipv4 **p)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-10-30 01:05:27 +01:00
|
|
|
prefix_free((struct prefix **)p);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2019-08-07 03:16:21 +02:00
|
|
|
/* If given string is valid return 1 else return 0 */
|
2004-10-04 21:10:31 +02:00
|
|
|
int str2prefix_ipv4(const char *str, struct prefix_ipv4 *p)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int plen;
|
|
|
|
char *pnt;
|
|
|
|
char *cp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Find slash inside string. */
|
|
|
|
pnt = strchr(str, '/');
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* String doesn't contail slash. */
|
|
|
|
if (pnt == NULL) {
|
|
|
|
/* Convert string to prefix. */
|
2018-11-28 12:15:09 +01:00
|
|
|
ret = inet_pton(AF_INET, str, &p->prefix);
|
2002-12-13 21:15:29 +01:00
|
|
|
if (ret == 0)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If address doesn't contain slash we assume it host address.
|
|
|
|
*/
|
|
|
|
p->family = AF_INET;
|
|
|
|
p->prefixlen = IPV4_MAX_BITLEN;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return ret;
|
|
|
|
} else {
|
|
|
|
cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1);
|
2019-02-26 21:25:24 +01:00
|
|
|
memcpy(cp, str, pnt - str);
|
2002-12-13 21:15:29 +01:00
|
|
|
*(cp + (pnt - str)) = '\0';
|
2019-08-07 03:13:20 +02:00
|
|
|
ret = inet_pton(AF_INET, cp, &p->prefix);
|
2002-12-13 21:15:29 +01:00
|
|
|
XFREE(MTYPE_TMP, cp);
|
2019-08-07 03:13:20 +02:00
|
|
|
if (ret == 0)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Get prefix length. */
|
2018-03-27 21:13:34 +02:00
|
|
|
plen = (uint8_t)atoi(++pnt);
|
2021-07-01 16:42:03 +02:00
|
|
|
if (plen > IPV4_MAX_BITLEN)
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
p->family = AF_INET;
|
|
|
|
p->prefixlen = plen;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-04-19 22:08:59 +02:00
|
|
|
/* When string format is invalid return 0. */
|
|
|
|
int str2prefix_eth(const char *str, struct prefix_eth *p)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int plen = 48;
|
|
|
|
char *pnt;
|
|
|
|
char *cp = NULL;
|
|
|
|
const char *str_addr = str;
|
|
|
|
unsigned int a[6];
|
|
|
|
int i;
|
2017-08-04 21:55:44 +02:00
|
|
|
bool slash = false;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-09 20:30:34 +02:00
|
|
|
if (!strcmp(str, "any")) {
|
|
|
|
memset(p, 0, sizeof(*p));
|
|
|
|
p->family = AF_ETHERNET;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-04-19 22:08:59 +02:00
|
|
|
/* Find slash inside string. */
|
|
|
|
pnt = strchr(str, '/');
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-04-19 22:08:59 +02:00
|
|
|
if (pnt) {
|
|
|
|
/* Get prefix length. */
|
2018-03-27 21:13:34 +02:00
|
|
|
plen = (uint8_t)atoi(++pnt);
|
2016-04-19 22:08:59 +02:00
|
|
|
if (plen > 48) {
|
|
|
|
ret = 0;
|
|
|
|
goto done;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2016-07-28 17:23:49 +02:00
|
|
|
cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1);
|
2019-02-26 21:25:24 +01:00
|
|
|
memcpy(cp, str, pnt - str);
|
2002-12-13 21:15:29 +01:00
|
|
|
*(cp + (pnt - str)) = '\0';
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-04-19 22:08:59 +02:00
|
|
|
str_addr = cp;
|
2017-08-04 21:55:44 +02:00
|
|
|
slash = true;
|
2016-04-19 22:08:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert string to prefix. */
|
|
|
|
if (sscanf(str_addr, "%2x:%2x:%2x:%2x:%2x:%2x", a + 0, a + 1, a + 2,
|
|
|
|
a + 3, a + 4, a + 5)
|
|
|
|
!= 6) {
|
|
|
|
ret = 0;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
for (i = 0; i < 6; ++i) {
|
|
|
|
p->eth_addr.octet[i] = a[i] & 0xff;
|
|
|
|
}
|
|
|
|
p->prefixlen = plen;
|
|
|
|
p->family = AF_ETHERNET;
|
2017-08-04 21:55:44 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* special case to allow old configurations to work
|
|
|
|
* Since all zero's is implicitly meant to allow
|
|
|
|
* a comparison to zero, let's assume
|
|
|
|
*/
|
|
|
|
if (!slash && is_zero_mac(&(p->eth_addr)))
|
|
|
|
p->prefixlen = 0;
|
|
|
|
|
2016-04-19 22:08:59 +02:00
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
done:
|
2019-02-25 21:18:13 +01:00
|
|
|
XFREE(MTYPE_TMP, cp);
|
2016-04-19 22:08:59 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-10-11 13:17:45 +02:00
|
|
|
/* Convert masklen into IP address's netmask (network byte order). */
|
2011-10-08 16:15:21 +02:00
|
|
|
void masklen2ip(const int masklen, struct in_addr *netmask)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2011-10-24 16:45:05 +02:00
|
|
|
assert(masklen >= 0 && masklen <= IPV4_MAX_BITLEN);
|
2012-04-04 00:14:36 +02:00
|
|
|
|
|
|
|
/* left shift is only defined for less than the size of the type.
|
|
|
|
* we unconditionally use long long in case the target platform
|
|
|
|
* has defined behaviour for << 32 (or has a 64-bit left shift) */
|
|
|
|
|
|
|
|
if (sizeof(unsigned long long) > 4)
|
|
|
|
netmask->s_addr = htonl(0xffffffffULL << (32 - masklen));
|
|
|
|
else
|
|
|
|
netmask->s_addr =
|
|
|
|
htonl(masklen ? 0xffffffffU << (32 - masklen) : 0);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert IP address's netmask into integer. We assume netmask is
|
2018-07-27 02:11:13 +02:00
|
|
|
* sequential one. Argument netmask should be network byte order. */
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t ip_masklen(struct in_addr netmask)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2012-04-04 00:14:36 +02:00
|
|
|
uint32_t tmp = ~ntohl(netmask.s_addr);
|
2018-07-27 02:11:13 +02:00
|
|
|
|
2018-10-25 22:24:25 +02:00
|
|
|
/*
|
|
|
|
* clz: count leading zeroes. sadly, the behaviour of this builtin is
|
|
|
|
* undefined for a 0 argument, even though most CPUs give 32
|
|
|
|
*/
|
2018-07-27 02:11:13 +02:00
|
|
|
return tmp ? __builtin_clz(tmp) : 32;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2011-10-18 16:33:53 +02:00
|
|
|
/* Apply mask to IPv4 prefix (network byte order). */
|
2002-12-13 21:15:29 +01:00
|
|
|
void apply_mask_ipv4(struct prefix_ipv4 *p)
|
|
|
|
{
|
2012-04-04 00:14:36 +02:00
|
|
|
struct in_addr mask;
|
|
|
|
masklen2ip(p->prefixlen, &mask);
|
|
|
|
p->prefix.s_addr &= mask.s_addr;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If prefix is 0.0.0.0/0 then return 1 else return 0. */
|
2004-10-04 21:10:31 +02:00
|
|
|
int prefix_ipv4_any(const struct prefix_ipv4 *p)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2020-02-06 07:49:02 +01:00
|
|
|
return (p->prefix.s_addr == INADDR_ANY && p->prefixlen == 0);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Allocate a new ip version 6 route */
|
2005-05-06 Paul Jakma <paul@dishone.st>
* (general) extern and static'ification of functions in code and
header.
Cleanup any definitions with unspecified arguments.
Add casts for callback assignments where the callback is defined,
typically, as passing void *, but the function being assigned has
some other pointer type defined as its argument, as gcc complains
about casts from void * to X* via function arguments.
Fix some old K&R style function argument definitions.
Add noreturn gcc attribute to some functions, as appropriate.
Add unused gcc attribute to some functions (eg ones meant to help
while debugging)
Add guard defines to headers which were missing them.
* command.c: (install_node) add const qualifier, still doesnt shut
up the warning though, because of the double pointer.
(cmp_node) ditto
* keychain.c: (key_str2time) Add GET_LONG_RANGE() macro, derived
fromn vty.h ones to fix some of the (long) < 0 warnings.
* thread.c: (various) use thread_empty
(cpu_record_hash_key) should cast to uintptr_t, a stdint.h type
* vty.h: Add VTY_GET_IPV4_ADDRESS and VTY_GET_IPV4_PREFIX so they
removed from ospfd/ospf_vty.h
* zebra.h: Move definition of ZEBRA_PORT to here, to remove
dependence of lib on zebra/zserv.h
2005-05-06 23:25:49 +02:00
|
|
|
struct prefix_ipv6 *prefix_ipv6_new(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct prefix_ipv6 *p;
|
|
|
|
|
2005-07-26 21:55:31 +02:00
|
|
|
/* Allocate a full-size struct prefix to avoid problems with structure
|
|
|
|
size mismatches. */
|
|
|
|
p = (struct prefix_ipv6 *)prefix_new();
|
2002-12-13 21:15:29 +01:00
|
|
|
p->family = AF_INET6;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free prefix for IPv6. */
|
2019-10-30 01:05:27 +01:00
|
|
|
void prefix_ipv6_free(struct prefix_ipv6 **p)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-10-30 01:05:27 +01:00
|
|
|
prefix_free((struct prefix **)p);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2019-08-07 03:16:21 +02:00
|
|
|
/* If given string is valid return 1 else return 0 */
|
2004-10-04 21:10:31 +02:00
|
|
|
int str2prefix_ipv6(const char *str, struct prefix_ipv6 *p)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
char *pnt;
|
|
|
|
char *cp;
|
|
|
|
int ret;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
pnt = strchr(str, '/');
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If string doesn't contain `/' treat it as host route. */
|
|
|
|
if (pnt == NULL) {
|
|
|
|
ret = inet_pton(AF_INET6, str, &p->prefix);
|
2009-08-08 21:41:39 +02:00
|
|
|
if (ret == 0)
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
|
|
|
p->prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
} else {
|
|
|
|
int plen;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-07-28 17:23:49 +02:00
|
|
|
cp = XMALLOC(MTYPE_TMP, (pnt - str) + 1);
|
2019-02-26 21:25:24 +01:00
|
|
|
memcpy(cp, str, pnt - str);
|
2002-12-13 21:15:29 +01:00
|
|
|
*(cp + (pnt - str)) = '\0';
|
|
|
|
ret = inet_pton(AF_INET6, cp, &p->prefix);
|
2016-11-07 13:33:15 +01:00
|
|
|
XFREE(MTYPE_TMP, cp);
|
2009-08-08 21:41:39 +02:00
|
|
|
if (ret == 0)
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
2018-03-27 21:13:34 +02:00
|
|
|
plen = (uint8_t)atoi(++pnt);
|
2011-10-24 16:45:05 +02:00
|
|
|
if (plen > IPV6_MAX_BITLEN)
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
|
|
|
p->prefixlen = plen;
|
|
|
|
}
|
|
|
|
p->family = AF_INET6;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2004-10-04 21:10:31 +02:00
|
|
|
/* Convert struct in6_addr netmask into integer.
|
2018-03-27 21:13:34 +02:00
|
|
|
* FIXME return uint8_t as ip_maskleni() does. */
|
2002-12-13 21:15:29 +01:00
|
|
|
int ip6_masklen(struct in6_addr netmask)
|
|
|
|
{
|
2019-11-27 21:43:27 +01:00
|
|
|
if (netmask.s6_addr32[0] != 0xffffffffU)
|
|
|
|
return __builtin_clz(~ntohl(netmask.s6_addr32[0]));
|
|
|
|
if (netmask.s6_addr32[1] != 0xffffffffU)
|
|
|
|
return __builtin_clz(~ntohl(netmask.s6_addr32[1])) + 32;
|
|
|
|
if (netmask.s6_addr32[2] != 0xffffffffU)
|
|
|
|
return __builtin_clz(~ntohl(netmask.s6_addr32[2])) + 64;
|
|
|
|
if (netmask.s6_addr32[3] != 0xffffffffU)
|
|
|
|
return __builtin_clz(~ntohl(netmask.s6_addr32[3])) + 96;
|
|
|
|
/* note __builtin_clz(0) is undefined */
|
|
|
|
return 128;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2011-10-17 19:11:10 +02:00
|
|
|
void masklen2ip6(const int masklen, struct in6_addr *netmask)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2011-10-24 16:45:05 +02:00
|
|
|
assert(masklen >= 0 && masklen <= IPV6_MAX_BITLEN);
|
2019-11-27 21:43:27 +01:00
|
|
|
|
|
|
|
if (masklen == 0) {
|
|
|
|
/* note << 32 is undefined */
|
|
|
|
memset(netmask, 0, sizeof(*netmask));
|
|
|
|
} else if (masklen <= 32) {
|
|
|
|
netmask->s6_addr32[0] = htonl(0xffffffffU << (32 - masklen));
|
|
|
|
netmask->s6_addr32[1] = 0;
|
|
|
|
netmask->s6_addr32[2] = 0;
|
|
|
|
netmask->s6_addr32[3] = 0;
|
|
|
|
} else if (masklen <= 64) {
|
|
|
|
netmask->s6_addr32[0] = 0xffffffffU;
|
|
|
|
netmask->s6_addr32[1] = htonl(0xffffffffU << (64 - masklen));
|
|
|
|
netmask->s6_addr32[2] = 0;
|
|
|
|
netmask->s6_addr32[3] = 0;
|
|
|
|
} else if (masklen <= 96) {
|
|
|
|
netmask->s6_addr32[0] = 0xffffffffU;
|
|
|
|
netmask->s6_addr32[1] = 0xffffffffU;
|
|
|
|
netmask->s6_addr32[2] = htonl(0xffffffffU << (96 - masklen));
|
|
|
|
netmask->s6_addr32[3] = 0;
|
|
|
|
} else {
|
|
|
|
netmask->s6_addr32[0] = 0xffffffffU;
|
|
|
|
netmask->s6_addr32[1] = 0xffffffffU;
|
|
|
|
netmask->s6_addr32[2] = 0xffffffffU;
|
|
|
|
netmask->s6_addr32[3] = htonl(0xffffffffU << (128 - masklen));
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void apply_mask_ipv6(struct prefix_ipv6 *p)
|
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t *pnt;
|
2012-01-01 13:33:12 +01:00
|
|
|
int index;
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
index = p->prefixlen / 8;
|
|
|
|
|
|
|
|
if (index < 16) {
|
2018-03-27 21:13:34 +02:00
|
|
|
pnt = (uint8_t *)&p->prefix;
|
2012-01-01 13:33:12 +01:00
|
|
|
offset = p->prefixlen % 8;
|
|
|
|
|
|
|
|
pnt[index] &= maskbit[offset];
|
|
|
|
index++;
|
|
|
|
|
|
|
|
while (index < 16)
|
|
|
|
pnt[index++] = 0;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2022-04-08 18:17:38 +02:00
|
|
|
void apply_mask(union prefixptr pu)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2022-04-08 18:17:38 +02:00
|
|
|
struct prefix *p = pu.p;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
switch (p->family) {
|
|
|
|
case AF_INET:
|
2022-04-08 18:17:38 +02:00
|
|
|
apply_mask_ipv4(pu.p4);
|
2002-12-13 21:15:29 +01:00
|
|
|
break;
|
|
|
|
case AF_INET6:
|
2022-04-08 18:17:38 +02:00
|
|
|
apply_mask_ipv6(pu.p6);
|
2002-12-13 21:15:29 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-10-04 21:10:31 +02:00
|
|
|
/* Utility function of convert between struct prefix <=> union sockunion. */
|
2015-05-22 12:40:57 +02:00
|
|
|
struct prefix *sockunion2hostprefix(const union sockunion *su,
|
|
|
|
struct prefix *prefix)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
if (su->sa.sa_family == AF_INET) {
|
|
|
|
struct prefix_ipv4 *p;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-22 12:40:57 +02:00
|
|
|
p = prefix ? (struct prefix_ipv4 *)prefix : prefix_ipv4_new();
|
2002-12-13 21:15:29 +01:00
|
|
|
p->family = AF_INET;
|
|
|
|
p->prefix = su->sin.sin_addr;
|
|
|
|
p->prefixlen = IPV4_MAX_BITLEN;
|
|
|
|
return (struct prefix *)p;
|
|
|
|
}
|
|
|
|
if (su->sa.sa_family == AF_INET6) {
|
|
|
|
struct prefix_ipv6 *p;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-22 12:40:57 +02:00
|
|
|
p = prefix ? (struct prefix_ipv6 *)prefix : prefix_ipv6_new();
|
2002-12-13 21:15:29 +01:00
|
|
|
p->family = AF_INET6;
|
|
|
|
p->prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
memcpy(&p->prefix, &su->sin6.sin6_addr,
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
return (struct prefix *)p;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-02 20:16:35 +01:00
|
|
|
void prefix2sockunion(const struct prefix *p, union sockunion *su)
|
|
|
|
{
|
|
|
|
memset(su, 0, sizeof(*su));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2010-02-02 20:16:35 +01:00
|
|
|
su->sa.sa_family = p->family;
|
|
|
|
if (p->family == AF_INET)
|
|
|
|
su->sin.sin_addr = p->u.prefix4;
|
|
|
|
if (p->family == AF_INET6)
|
|
|
|
memcpy(&su->sin6.sin6_addr, &p->u.prefix6,
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
}
|
|
|
|
|
2022-04-08 18:17:38 +02:00
|
|
|
int prefix_blen(union prefixconstptr pu)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2022-04-08 18:17:38 +02:00
|
|
|
const struct prefix *p = pu.p;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
switch (p->family) {
|
|
|
|
case AF_INET:
|
|
|
|
return IPV4_MAX_BYTELEN;
|
|
|
|
case AF_INET6:
|
|
|
|
return IPV6_MAX_BYTELEN;
|
2016-04-19 22:08:59 +02:00
|
|
|
case AF_ETHERNET:
|
2017-08-03 14:42:29 +02:00
|
|
|
return ETH_ALEN;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Generic function for conversion string to struct prefix. */
|
2004-10-04 21:10:31 +02:00
|
|
|
int str2prefix(const char *str, struct prefix *p)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2018-06-18 12:23:28 +02:00
|
|
|
if (!str || !p)
|
|
|
|
return 0;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* First we try to convert string to struct prefix_ipv4. */
|
|
|
|
ret = str2prefix_ipv4(str, (struct prefix_ipv4 *)p);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* Next we try to convert string to struct prefix_ipv6. */
|
|
|
|
ret = str2prefix_ipv6(str, (struct prefix_ipv6 *)p);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2016-04-19 22:08:59 +02:00
|
|
|
/* Next we try to convert string to struct prefix_eth. */
|
|
|
|
ret = str2prefix_eth(str, (struct prefix_eth *)p);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-04-14 00:37:30 +02:00
|
|
|
static const char *prefixevpn_ead2str(const struct prefix_evpn *p, char *str,
|
|
|
|
int size)
|
|
|
|
{
|
2020-10-15 15:25:26 +02:00
|
|
|
uint8_t family;
|
2020-10-15 13:24:51 +02:00
|
|
|
char buf[ESI_STR_LEN];
|
2020-10-15 15:25:26 +02:00
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
2020-10-15 13:24:51 +02:00
|
|
|
|
2020-10-15 15:25:26 +02:00
|
|
|
family = IS_IPADDR_V4(&p->prefix.ead_addr.ip) ? AF_INET : AF_INET6;
|
lib, bgpd: changes for EAD-per-ES fragmentation
The EAD-per-ES route carries ECs for all the ES-EVI RTs. As the number of VNIs
increase all RTs do not fit into a standard BGP UPDATE (4K) so the route needs
to be fragmented.
Each fragment is associated with a separate RD and frag-id -
1. Local ES-per-EAD -
ES route table - {ES-frag-ID, ESI, ET=0xffffffff, VTEP-IP}
global route table - {RD-=ES-frag-RD, ESI, ET=0xffffffff}
2. Remote ES-per-EAD -
VNI route table - {ESI, ET=0xffffffff, VTEP-IP}
global route table - {RD-=ES-frag-RD, ESI, ET=0xffffffff}
Note: The fragment ID is abandoned in the per-VNI routing table. At this
point that is acceptable as we dont expect more than one-ES-per-EAD fragment
to be imported into the per-VNI routing table. But that may need to be
re-worked at a later point.
CLI changes (sample with 4 VNIs per-fragment for experimental pruposes) -
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
root@torm-11:mgmt:~# vtysh -c "show bgp l2vpn evpn es 03:44:38:39:ff:ff:01:00:00:01"
ESI: 03:44:38:39:ff:ff:01:00:00:01
Type: LR
RD: 27.0.0.21:3
Originator-IP: 27.0.0.21
Local ES DF preference: 50000
VNI Count: 10
Remote VNI Count: 10
VRF Count: 3
MACIP EVI Path Count: 33
MACIP Global Path Count: 198
Inconsistent VNI VTEP Count: 0
Inconsistencies: -
Fragments: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
27.0.0.21:3 EVIs: 4
27.0.0.21:13 EVIs: 4
27.0.0.21:22 EVIs: 2
VTEPs:
27.0.0.22 flags: EA df_alg: preference df_pref: 32767
27.0.0.23 flags: EA df_alg: preference df_pref: 32767
root@torm-11:mgmt:~# vtysh -c "show bgp l2vpn evpn es-evi vni 1002 detail"
VNI: 1002 ESI: 03:44:38:39:ff:ff:01:00:00:01
Type: LR
ES fragment RD: 27.0.0.21:13 >>>>>>>>>>>>>>>>>>>>>>>>>
Inconsistencies: -
VTEPs: 27.0.0.22(EV),27.0.0.23(EV)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
PS: The number of EVIs per-fragment has been set to 128 and may need further
tuning.
Ticket: #2632967
Signed-off-by: Anuradha Karuppiah <anuradhak@nvidia.com>
2021-06-04 02:28:43 +02:00
|
|
|
snprintf(str, size, "[%d]:[%u]:[%s]:[%d]:[%s]:[%u]",
|
|
|
|
p->prefix.route_type, p->prefix.ead_addr.eth_tag,
|
2020-10-15 13:24:51 +02:00
|
|
|
esi_to_str(&p->prefix.ead_addr.esi, buf, sizeof(buf)),
|
2020-10-15 15:25:26 +02:00
|
|
|
(family == AF_INET) ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN,
|
|
|
|
inet_ntop(family, &p->prefix.ead_addr.ip.ipaddr_v4, buf1,
|
lib, bgpd: changes for EAD-per-ES fragmentation
The EAD-per-ES route carries ECs for all the ES-EVI RTs. As the number of VNIs
increase all RTs do not fit into a standard BGP UPDATE (4K) so the route needs
to be fragmented.
Each fragment is associated with a separate RD and frag-id -
1. Local ES-per-EAD -
ES route table - {ES-frag-ID, ESI, ET=0xffffffff, VTEP-IP}
global route table - {RD-=ES-frag-RD, ESI, ET=0xffffffff}
2. Remote ES-per-EAD -
VNI route table - {ESI, ET=0xffffffff, VTEP-IP}
global route table - {RD-=ES-frag-RD, ESI, ET=0xffffffff}
Note: The fragment ID is abandoned in the per-VNI routing table. At this
point that is acceptable as we dont expect more than one-ES-per-EAD fragment
to be imported into the per-VNI routing table. But that may need to be
re-worked at a later point.
CLI changes (sample with 4 VNIs per-fragment for experimental pruposes) -
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
root@torm-11:mgmt:~# vtysh -c "show bgp l2vpn evpn es 03:44:38:39:ff:ff:01:00:00:01"
ESI: 03:44:38:39:ff:ff:01:00:00:01
Type: LR
RD: 27.0.0.21:3
Originator-IP: 27.0.0.21
Local ES DF preference: 50000
VNI Count: 10
Remote VNI Count: 10
VRF Count: 3
MACIP EVI Path Count: 33
MACIP Global Path Count: 198
Inconsistent VNI VTEP Count: 0
Inconsistencies: -
Fragments: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
27.0.0.21:3 EVIs: 4
27.0.0.21:13 EVIs: 4
27.0.0.21:22 EVIs: 2
VTEPs:
27.0.0.22 flags: EA df_alg: preference df_pref: 32767
27.0.0.23 flags: EA df_alg: preference df_pref: 32767
root@torm-11:mgmt:~# vtysh -c "show bgp l2vpn evpn es-evi vni 1002 detail"
VNI: 1002 ESI: 03:44:38:39:ff:ff:01:00:00:01
Type: LR
ES fragment RD: 27.0.0.21:13 >>>>>>>>>>>>>>>>>>>>>>>>>
Inconsistencies: -
VTEPs: 27.0.0.22(EV),27.0.0.23(EV)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
PS: The number of EVIs per-fragment has been set to 128 and may need further
tuning.
Ticket: #2632967
Signed-off-by: Anuradha Karuppiah <anuradhak@nvidia.com>
2021-06-04 02:28:43 +02:00
|
|
|
sizeof(buf1)),
|
|
|
|
p->prefix.ead_addr.frag_id);
|
2018-04-14 00:37:30 +02:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *prefixevpn_macip2str(const struct prefix_evpn *p, char *str,
|
|
|
|
int size)
|
2017-05-15 07:20:33 +02:00
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t family;
|
2020-10-15 13:24:51 +02:00
|
|
|
char buf1[ETHER_ADDR_STRLEN];
|
|
|
|
char buf2[PREFIX2STR_BUFFER];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-04-14 00:37:30 +02:00
|
|
|
if (is_evpn_prefix_ipaddr_none(p))
|
2020-10-15 13:24:51 +02:00
|
|
|
snprintf(str, size, "[%d]:[%d]:[%d]:[%s]", p->prefix.route_type,
|
|
|
|
p->prefix.macip_addr.eth_tag, 8 * ETH_ALEN,
|
|
|
|
prefix_mac2str(&p->prefix.macip_addr.mac, buf1,
|
|
|
|
sizeof(buf1)));
|
2018-04-14 00:37:30 +02:00
|
|
|
else {
|
2020-10-15 13:24:51 +02:00
|
|
|
family = is_evpn_prefix_ipaddr_v4(p) ? AF_INET : AF_INET6;
|
|
|
|
snprintf(str, size, "[%d]:[%d]:[%d]:[%s]:[%d]:[%s]",
|
|
|
|
p->prefix.route_type, p->prefix.macip_addr.eth_tag,
|
|
|
|
8 * ETH_ALEN,
|
|
|
|
prefix_mac2str(&p->prefix.macip_addr.mac, buf1,
|
|
|
|
sizeof(buf1)),
|
|
|
|
family == AF_INET ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN,
|
|
|
|
inet_ntop(family, &p->prefix.macip_addr.ip.ip.addr,
|
|
|
|
buf2, PREFIX2STR_BUFFER));
|
2017-05-15 07:20:33 +02:00
|
|
|
}
|
2018-04-14 00:37:30 +02:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *prefixevpn_imet2str(const struct prefix_evpn *p, char *str,
|
|
|
|
int size)
|
|
|
|
{
|
2020-10-15 15:25:26 +02:00
|
|
|
uint8_t family;
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
family = IS_IPADDR_V4(&p->prefix.imet_addr.ip) ? AF_INET : AF_INET6;
|
2020-10-15 13:24:51 +02:00
|
|
|
snprintf(str, size, "[%d]:[%d]:[%d]:[%s]", p->prefix.route_type,
|
|
|
|
p->prefix.imet_addr.eth_tag,
|
2020-10-15 15:25:26 +02:00
|
|
|
(family == AF_INET) ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN,
|
|
|
|
inet_ntop(family, &p->prefix.imet_addr.ip.ipaddr_v4, buf,
|
|
|
|
sizeof(buf)));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-04-14 00:37:30 +02:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *prefixevpn_es2str(const struct prefix_evpn *p, char *str,
|
|
|
|
int size)
|
|
|
|
{
|
2020-10-15 15:25:26 +02:00
|
|
|
uint8_t family;
|
2018-04-14 00:01:12 +02:00
|
|
|
char buf[ESI_STR_LEN];
|
2020-10-15 15:25:26 +02:00
|
|
|
char buf1[INET6_ADDRSTRLEN];
|
2018-04-14 00:01:12 +02:00
|
|
|
|
2020-10-15 15:25:26 +02:00
|
|
|
family = IS_IPADDR_V4(&p->prefix.es_addr.ip) ? AF_INET : AF_INET6;
|
2020-10-15 13:24:51 +02:00
|
|
|
snprintf(str, size, "[%d]:[%s]:[%d]:[%s]", p->prefix.route_type,
|
2018-04-14 00:01:12 +02:00
|
|
|
esi_to_str(&p->prefix.es_addr.esi, buf, sizeof(buf)),
|
2020-10-15 15:25:26 +02:00
|
|
|
(family == AF_INET) ? IPV4_MAX_BITLEN : IPV6_MAX_BITLEN,
|
|
|
|
inet_ntop(family, &p->prefix.es_addr.ip.ipaddr_v4, buf1,
|
|
|
|
sizeof(buf1)));
|
2020-10-15 13:24:51 +02:00
|
|
|
|
2018-04-14 00:37:30 +02:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *prefixevpn_prefix2str(const struct prefix_evpn *p, char *str,
|
|
|
|
int size)
|
|
|
|
{
|
2020-10-15 15:25:26 +02:00
|
|
|
uint8_t family;
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
family = IS_IPADDR_V4(&p->prefix.prefix_addr.ip) ? AF_INET : AF_INET6;
|
2020-10-15 13:24:51 +02:00
|
|
|
snprintf(str, size, "[%d]:[%d]:[%d]:[%s]", p->prefix.route_type,
|
2018-04-14 00:37:30 +02:00
|
|
|
p->prefix.prefix_addr.eth_tag,
|
|
|
|
p->prefix.prefix_addr.ip_prefix_length,
|
2020-10-15 15:25:26 +02:00
|
|
|
inet_ntop(family, &p->prefix.prefix_addr.ip.ipaddr_v4, buf,
|
|
|
|
sizeof(buf)));
|
2018-04-14 00:37:30 +02:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *prefixevpn2str(const struct prefix_evpn *p, char *str,
|
|
|
|
int size)
|
|
|
|
{
|
|
|
|
switch (p->prefix.route_type) {
|
2020-10-15 13:24:51 +02:00
|
|
|
case BGP_EVPN_AD_ROUTE:
|
2018-04-14 00:37:30 +02:00
|
|
|
return prefixevpn_ead2str(p, str, size);
|
2020-10-15 13:24:51 +02:00
|
|
|
case BGP_EVPN_MAC_IP_ROUTE:
|
2018-04-14 00:37:30 +02:00
|
|
|
return prefixevpn_macip2str(p, str, size);
|
2020-10-15 13:24:51 +02:00
|
|
|
case BGP_EVPN_IMET_ROUTE:
|
2018-04-14 00:37:30 +02:00
|
|
|
return prefixevpn_imet2str(p, str, size);
|
2020-10-15 13:24:51 +02:00
|
|
|
case BGP_EVPN_ES_ROUTE:
|
2018-04-14 00:37:30 +02:00
|
|
|
return prefixevpn_es2str(p, str, size);
|
2020-10-15 13:24:51 +02:00
|
|
|
case BGP_EVPN_IP_PREFIX_ROUTE:
|
2018-04-14 00:37:30 +02:00
|
|
|
return prefixevpn_prefix2str(p, str, size);
|
|
|
|
default:
|
|
|
|
snprintf(str, size, "Unsupported EVPN prefix");
|
|
|
|
break;
|
|
|
|
}
|
2017-05-15 07:20:33 +02:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2016-08-10 00:55:51 +02:00
|
|
|
const char *prefix2str(union prefixconstptr pu, char *str, int size)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2015-05-22 11:40:02 +02:00
|
|
|
const struct prefix *p = pu.p;
|
2016-08-10 00:55:51 +02:00
|
|
|
char buf[PREFIX2STR_BUFFER];
|
2019-06-13 19:08:05 +02:00
|
|
|
int byte, tmp, a, b;
|
|
|
|
bool z = false;
|
|
|
|
size_t l;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-10 00:55:51 +02:00
|
|
|
switch (p->family) {
|
|
|
|
case AF_INET:
|
|
|
|
case AF_INET6:
|
2019-06-13 19:08:05 +02:00
|
|
|
inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
|
|
|
|
l = strlen(buf);
|
|
|
|
buf[l++] = '/';
|
|
|
|
byte = p->prefixlen;
|
2021-06-29 13:43:16 +02:00
|
|
|
tmp = p->prefixlen - 100;
|
|
|
|
if (tmp >= 0) {
|
2019-06-13 19:08:05 +02:00
|
|
|
buf[l++] = '1';
|
|
|
|
z = true;
|
|
|
|
byte = tmp;
|
|
|
|
}
|
|
|
|
b = byte % 10;
|
|
|
|
a = byte / 10;
|
|
|
|
if (a || z)
|
|
|
|
buf[l++] = '0' + a;
|
|
|
|
buf[l++] = '0' + b;
|
|
|
|
buf[l] = '\0';
|
|
|
|
strlcpy(str, buf, size);
|
2016-08-10 00:55:51 +02:00
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-08-10 00:55:51 +02:00
|
|
|
case AF_ETHERNET:
|
2017-08-08 16:16:12 +02:00
|
|
|
snprintf(str, size, "%s/%d",
|
|
|
|
prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf)),
|
|
|
|
p->prefixlen);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_EVPN:
|
2018-04-14 00:37:30 +02:00
|
|
|
prefixevpn2str((const struct prefix_evpn *)p, str, size);
|
2016-08-10 00:55:51 +02:00
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-01-10 19:13:27 +01:00
|
|
|
case AF_FLOWSPEC:
|
2019-06-13 19:08:05 +02:00
|
|
|
strlcpy(str, "FS prefix", size);
|
2018-01-10 19:13:27 +01:00
|
|
|
break;
|
|
|
|
|
2016-08-10 00:55:51 +02:00
|
|
|
default:
|
2019-06-13 19:08:05 +02:00
|
|
|
strlcpy(str, "UNK prefix", size);
|
2016-08-10 00:55:51 +02:00
|
|
|
break;
|
2016-04-19 22:08:59 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2015-05-22 11:40:02 +02:00
|
|
|
return str;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2022-03-11 11:59:38 +01:00
|
|
|
static ssize_t prefixhost2str(struct fbuf *fbuf, union prefixconstptr pu)
|
|
|
|
{
|
|
|
|
const struct prefix *p = pu.p;
|
|
|
|
char buf[PREFIX2STR_BUFFER];
|
|
|
|
|
|
|
|
switch (p->family) {
|
|
|
|
case AF_INET:
|
|
|
|
case AF_INET6:
|
|
|
|
inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
|
|
|
|
return bputs(fbuf, buf);
|
|
|
|
|
|
|
|
case AF_ETHERNET:
|
|
|
|
prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf));
|
|
|
|
return bputs(fbuf, buf);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return bprintfrr(fbuf, "{prefix.af=%dPF}", p->family);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-19 19:36:41 +01:00
|
|
|
void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
|
|
|
|
char *buf, int buf_size)
|
|
|
|
{
|
|
|
|
int save_errno = errno;
|
|
|
|
|
|
|
|
if (addr.s_addr == INADDR_ANY)
|
2019-05-06 23:05:20 +02:00
|
|
|
strlcpy(buf, "*", buf_size);
|
2019-03-19 19:36:41 +01:00
|
|
|
else {
|
|
|
|
if (!inet_ntop(AF_INET, &addr, buf, buf_size)) {
|
|
|
|
if (onfail)
|
|
|
|
snprintf(buf, buf_size, "%s", onfail);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
errno = save_errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *prefix_sg2str(const struct prefix_sg *sg, char *sg_str)
|
|
|
|
{
|
|
|
|
char src_str[INET_ADDRSTRLEN];
|
|
|
|
char grp_str[INET_ADDRSTRLEN];
|
|
|
|
|
|
|
|
prefix_mcast_inet4_dump("<src?>", sg->src, src_str, sizeof(src_str));
|
|
|
|
prefix_mcast_inet4_dump("<grp?>", sg->grp, grp_str, sizeof(grp_str));
|
|
|
|
snprintf(sg_str, PREFIX_SG_STR_LEN, "(%s,%s)", src_str, grp_str);
|
|
|
|
|
|
|
|
return sg_str;
|
|
|
|
}
|
|
|
|
|
2019-01-24 10:12:36 +01:00
|
|
|
struct prefix *prefix_new(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct prefix *p;
|
|
|
|
|
2020-03-08 20:43:26 +01:00
|
|
|
p = XCALLOC(MTYPE_PREFIX, sizeof(*p));
|
2002-12-13 21:15:29 +01:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2019-10-30 01:05:27 +01:00
|
|
|
void prefix_free_lists(void *arg)
|
|
|
|
{
|
|
|
|
struct prefix *p = arg;
|
|
|
|
|
|
|
|
prefix_free(&p);
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Free prefix structure. */
|
2019-10-30 01:05:27 +01:00
|
|
|
void prefix_free(struct prefix **p)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-10-30 01:05:27 +01:00
|
|
|
XFREE(MTYPE_PREFIX, *p);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Utility function to convert ipv4 prefixes to Classful prefixes */
|
|
|
|
void apply_classful_mask_ipv4(struct prefix_ipv4 *p)
|
|
|
|
{
|
|
|
|
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t destination;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
destination = ntohl(p->prefix.s_addr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-07-01 16:42:03 +02:00
|
|
|
if (p->prefixlen == IPV4_MAX_BITLEN)
|
2004-10-19 21:44:43 +02:00
|
|
|
;
|
2002-12-13 21:15:29 +01:00
|
|
|
/* do nothing for host routes */
|
|
|
|
else if (IN_CLASSC(destination)) {
|
|
|
|
p->prefixlen = 24;
|
|
|
|
apply_mask_ipv4(p);
|
|
|
|
} else if (IN_CLASSB(destination)) {
|
|
|
|
p->prefixlen = 16;
|
|
|
|
apply_mask_ipv4(p);
|
|
|
|
} else {
|
|
|
|
p->prefixlen = 8;
|
|
|
|
apply_mask_ipv4(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-19 21:44:43 +02:00
|
|
|
in_addr_t ipv4_broadcast_addr(in_addr_t hostaddr, int masklen)
|
|
|
|
{
|
|
|
|
struct in_addr mask;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-19 21:44:43 +02:00
|
|
|
masklen2ip(masklen, &mask);
|
2021-07-01 16:42:03 +02:00
|
|
|
return (masklen != IPV4_MAX_BITLEN - 1)
|
|
|
|
?
|
|
|
|
/* normal case */
|
|
|
|
(hostaddr | ~mask.s_addr)
|
|
|
|
:
|
|
|
|
/* For prefix 31 return 255.255.255.255 (RFC3021) */
|
|
|
|
htonl(0xFFFFFFFF);
|
2004-10-19 21:44:43 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Utility function to convert ipv4 netmask to prefixes
|
|
|
|
ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16"
|
|
|
|
ex.) "1.0.0.0" NULL => "1.0.0.0/8" */
|
2004-10-04 21:10:31 +02:00
|
|
|
int netmask_str2prefix_str(const char *net_str, const char *mask_str,
|
2021-02-08 04:39:42 +01:00
|
|
|
char *prefix_str, size_t prefix_str_len)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct in_addr network;
|
|
|
|
struct in_addr mask;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t prefixlen;
|
|
|
|
uint32_t destination;
|
2002-12-13 21:15:29 +01:00
|
|
|
int ret;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
ret = inet_aton(net_str, &network);
|
|
|
|
if (!ret)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (mask_str) {
|
|
|
|
ret = inet_aton(mask_str, &mask);
|
|
|
|
if (!ret)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
prefixlen = ip_masklen(mask);
|
|
|
|
} else {
|
|
|
|
destination = ntohl(network.s_addr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-02-06 07:49:02 +01:00
|
|
|
if (network.s_addr == INADDR_ANY)
|
2002-12-13 21:15:29 +01:00
|
|
|
prefixlen = 0;
|
|
|
|
else if (IN_CLASSC(destination))
|
|
|
|
prefixlen = 24;
|
|
|
|
else if (IN_CLASSB(destination))
|
|
|
|
prefixlen = 16;
|
|
|
|
else if (IN_CLASSA(destination))
|
|
|
|
prefixlen = 8;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-02-08 04:39:42 +01:00
|
|
|
snprintf(prefix_str, prefix_str_len, "%s/%d", net_str, prefixlen);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-02-01 18:26:34 +01:00
|
|
|
/* converts to internal representation of mac address
|
|
|
|
* returns 1 on success, 0 otherwise
|
|
|
|
* format accepted: AA:BB:CC:DD:EE:FF
|
|
|
|
* if mac parameter is null, then check only
|
|
|
|
*/
|
2017-02-09 08:42:32 +01:00
|
|
|
int prefix_str2mac(const char *str, struct ethaddr *mac)
|
2017-02-01 18:26:34 +01:00
|
|
|
{
|
2017-02-09 08:42:32 +01:00
|
|
|
unsigned int a[6];
|
|
|
|
int i;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-01 18:26:34 +01:00
|
|
|
if (!str)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-09 08:42:32 +01:00
|
|
|
if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x", a + 0, a + 1, a + 2, a + 3,
|
|
|
|
a + 4, a + 5)
|
|
|
|
!= 6) {
|
|
|
|
/* error in incoming str length */
|
2017-02-01 18:26:34 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2017-02-09 08:42:32 +01:00
|
|
|
/* valid mac address */
|
|
|
|
if (!mac)
|
|
|
|
return 1;
|
|
|
|
for (i = 0; i < 6; ++i)
|
|
|
|
mac->octet[i] = a[i] & 0xff;
|
2017-02-01 18:26:34 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-02-09 08:42:32 +01:00
|
|
|
char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size)
|
2017-02-01 18:26:34 +01:00
|
|
|
{
|
|
|
|
char *ptr;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-02-01 18:26:34 +01:00
|
|
|
if (!mac)
|
|
|
|
return NULL;
|
|
|
|
if (!buf)
|
2019-02-25 21:30:31 +01:00
|
|
|
ptr = XMALLOC(MTYPE_TMP, ETHER_ADDR_STRLEN * sizeof(char));
|
2017-02-01 18:26:34 +01:00
|
|
|
else {
|
2017-02-01 19:05:19 +01:00
|
|
|
assert(size >= ETHER_ADDR_STRLEN);
|
|
|
|
ptr = buf;
|
|
|
|
}
|
2017-02-09 08:42:32 +01:00
|
|
|
snprintf(ptr, (ETHER_ADDR_STRLEN), "%02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
(uint8_t)mac->octet[0], (uint8_t)mac->octet[1],
|
|
|
|
(uint8_t)mac->octet[2], (uint8_t)mac->octet[3],
|
|
|
|
(uint8_t)mac->octet[4], (uint8_t)mac->octet[5]);
|
2017-02-01 18:26:34 +01:00
|
|
|
return ptr;
|
|
|
|
}
|
2017-08-03 13:37:38 +02:00
|
|
|
|
2019-05-01 01:40:11 +02:00
|
|
|
unsigned prefix_hash_key(const void *pp)
|
2017-08-03 13:37:38 +02:00
|
|
|
{
|
|
|
|
struct prefix copy;
|
|
|
|
|
2018-01-10 19:13:27 +01:00
|
|
|
if (((struct prefix *)pp)->family == AF_FLOWSPEC) {
|
|
|
|
uint32_t len;
|
|
|
|
void *temp;
|
|
|
|
|
|
|
|
/* make sure *all* unused bits are zero,
|
|
|
|
* particularly including alignment /
|
|
|
|
* padding and unused prefix bytes.
|
|
|
|
*/
|
|
|
|
memset(©, 0, sizeof(copy));
|
|
|
|
prefix_copy(©, (struct prefix *)pp);
|
|
|
|
len = jhash((void *)copy.u.prefix_flowspec.ptr,
|
|
|
|
copy.u.prefix_flowspec.prefixlen,
|
|
|
|
0x55aa5a5a);
|
|
|
|
temp = (void *)copy.u.prefix_flowspec.ptr;
|
|
|
|
XFREE(MTYPE_PREFIX_FLOWSPEC, temp);
|
|
|
|
copy.u.prefix_flowspec.ptr = (uintptr_t)NULL;
|
|
|
|
return len;
|
|
|
|
}
|
2017-08-03 13:37:38 +02:00
|
|
|
/* make sure *all* unused bits are zero, particularly including
|
|
|
|
* alignment /
|
|
|
|
* padding and unused prefix bytes. */
|
|
|
|
memset(©, 0, sizeof(copy));
|
|
|
|
prefix_copy(©, (struct prefix *)pp);
|
2017-08-23 18:51:18 +02:00
|
|
|
return jhash(©,
|
|
|
|
offsetof(struct prefix, u.prefix) + PSIZE(copy.prefixlen),
|
|
|
|
0x55aa5a5a);
|
2017-08-03 13:37:38 +02:00
|
|
|
}
|
2018-04-14 00:01:12 +02:00
|
|
|
|
|
|
|
/* converts to internal representation of esi
|
|
|
|
* returns 1 on success, 0 otherwise
|
|
|
|
* format accepted: aa:aa:aa:aa:aa:aa:aa:aa:aa:aa
|
|
|
|
* if esi parameter is null, then check only
|
|
|
|
*/
|
|
|
|
int str_to_esi(const char *str, esi_t *esi)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned int a[ESI_BYTES];
|
|
|
|
|
|
|
|
if (!str)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x",
|
|
|
|
a + 0, a + 1, a + 2, a + 3,
|
|
|
|
a + 4, a + 5, a + 6, a + 7,
|
|
|
|
a + 8, a + 9)
|
|
|
|
!= ESI_BYTES) {
|
|
|
|
/* error in incoming str length */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* valid ESI */
|
|
|
|
if (!esi)
|
|
|
|
return 1;
|
|
|
|
for (i = 0; i < ESI_BYTES; ++i)
|
|
|
|
esi->val[i] = a[i] & 0xff;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *esi_to_str(const esi_t *esi, char *buf, int size)
|
|
|
|
{
|
|
|
|
char *ptr;
|
|
|
|
|
|
|
|
if (!esi)
|
|
|
|
return NULL;
|
|
|
|
if (!buf)
|
2019-02-25 21:30:31 +01:00
|
|
|
ptr = XMALLOC(MTYPE_TMP, ESI_STR_LEN * sizeof(char));
|
2018-04-14 00:01:12 +02:00
|
|
|
else {
|
|
|
|
assert(size >= ESI_STR_LEN);
|
|
|
|
ptr = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
snprintf(ptr, ESI_STR_LEN,
|
|
|
|
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
esi->val[0], esi->val[1], esi->val[2],
|
|
|
|
esi->val[3], esi->val[4], esi->val[5],
|
|
|
|
esi->val[6], esi->val[7], esi->val[8],
|
|
|
|
esi->val[9]);
|
|
|
|
return ptr;
|
|
|
|
}
|
2019-05-14 16:28:31 +02:00
|
|
|
|
2020-05-09 01:35:09 +02:00
|
|
|
char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len)
|
|
|
|
{
|
|
|
|
switch (df_alg) {
|
|
|
|
case EVPN_MH_DF_ALG_SERVICE_CARVING:
|
|
|
|
snprintf(buf, buf_len, "service-carving");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EVPN_MH_DF_ALG_HRW:
|
|
|
|
snprintf(buf, buf_len, "HRW");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EVPN_MH_DF_ALG_PREF:
|
|
|
|
snprintf(buf, buf_len, "preference");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
snprintf(buf, buf_len, "unknown %u", df_alg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2022-07-01 22:26:24 +02:00
|
|
|
bool ipv4_unicast_valid(const struct in_addr *addr)
|
|
|
|
{
|
|
|
|
in_addr_t ip = ntohl(addr->s_addr);
|
|
|
|
|
|
|
|
if (IPV4_CLASS_D(ip))
|
|
|
|
return false;
|
|
|
|
|
2023-02-20 16:34:26 +01:00
|
|
|
if (IPV4_NET0(ip) || IPV4_NET127(ip) || IPV4_CLASS_E(ip)) {
|
2022-07-01 22:26:24 +02:00
|
|
|
if (cmd_allow_reserved_ranges_get())
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-03-10 00:59:09 +01:00
|
|
|
static int ipaddr2prefix(const struct ipaddr *ip, uint16_t prefixlen,
|
|
|
|
struct prefix *p)
|
|
|
|
{
|
|
|
|
switch (ip->ipa_type) {
|
|
|
|
case (IPADDR_V4):
|
|
|
|
p->family = AF_INET;
|
|
|
|
p->u.prefix4 = ip->ipaddr_v4;
|
|
|
|
p->prefixlen = prefixlen;
|
|
|
|
break;
|
|
|
|
case (IPADDR_V6):
|
|
|
|
p->family = AF_INET6;
|
|
|
|
p->u.prefix6 = ip->ipaddr_v6;
|
|
|
|
p->prefixlen = prefixlen;
|
|
|
|
break;
|
|
|
|
case (IPADDR_NONE):
|
|
|
|
p->family = AF_UNSPEC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Convert type-2 and type-5 evpn route prefixes into the more
|
|
|
|
* general ipv4/ipv6 prefix types so we can match prefix lists
|
|
|
|
* and such.
|
|
|
|
*/
|
|
|
|
int evpn_prefix2prefix(const struct prefix *evpn, struct prefix *to)
|
|
|
|
{
|
|
|
|
const struct evpn_addr *addr;
|
|
|
|
|
|
|
|
if (evpn->family != AF_EVPN)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
addr = &evpn->u.prefix_evpn;
|
|
|
|
|
|
|
|
switch (addr->route_type) {
|
2022-03-11 19:28:30 +01:00
|
|
|
case BGP_EVPN_MAC_IP_ROUTE:
|
2021-03-10 00:59:09 +01:00
|
|
|
if (IS_IPADDR_V4(&addr->macip_addr.ip))
|
2023-02-17 21:41:13 +01:00
|
|
|
ipaddr2prefix(&addr->macip_addr.ip, IPV4_MAX_BITLEN,
|
|
|
|
to);
|
2021-03-10 00:59:09 +01:00
|
|
|
else if (IS_IPADDR_V6(&addr->macip_addr.ip))
|
2023-02-17 21:41:13 +01:00
|
|
|
ipaddr2prefix(&addr->macip_addr.ip, IPV6_MAX_BITLEN,
|
|
|
|
to);
|
2021-03-10 00:59:09 +01:00
|
|
|
else
|
|
|
|
return -1; /* mac only? */
|
|
|
|
|
|
|
|
break;
|
2022-03-11 19:28:30 +01:00
|
|
|
case BGP_EVPN_IP_PREFIX_ROUTE:
|
2021-03-10 00:59:09 +01:00
|
|
|
ipaddr2prefix(&addr->prefix_addr.ip,
|
|
|
|
addr->prefix_addr.ip_prefix_length, to);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-14 11:56:25 +01:00
|
|
|
printfrr_ext_autoreg_p("EA", printfrr_ea);
|
2021-03-20 09:02:04 +01:00
|
|
|
static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea,
|
|
|
|
const void *ptr)
|
2020-03-29 11:39:12 +02:00
|
|
|
{
|
|
|
|
const struct ethaddr *mac = ptr;
|
2021-02-18 22:52:23 +01:00
|
|
|
char cbuf[ETHER_ADDR_STRLEN];
|
2020-03-29 11:39:12 +02:00
|
|
|
|
2021-02-18 22:52:23 +01:00
|
|
|
if (!mac)
|
2021-03-26 19:14:24 +01:00
|
|
|
return bputs(buf, "(null)");
|
2021-03-01 21:41:30 +01:00
|
|
|
|
2021-02-18 22:52:23 +01:00
|
|
|
/* need real length even if buffer is too short */
|
|
|
|
prefix_mac2str(mac, cbuf, sizeof(cbuf));
|
|
|
|
return bputs(buf, cbuf);
|
2020-03-29 11:39:12 +02:00
|
|
|
}
|
|
|
|
|
2022-01-14 11:56:25 +01:00
|
|
|
printfrr_ext_autoreg_p("IA", printfrr_ia);
|
2021-03-20 09:02:04 +01:00
|
|
|
static ssize_t printfrr_ia(struct fbuf *buf, struct printfrr_eargs *ea,
|
|
|
|
const void *ptr)
|
2020-03-29 11:09:14 +02:00
|
|
|
{
|
|
|
|
const struct ipaddr *ipa = ptr;
|
2021-02-18 22:52:23 +01:00
|
|
|
char cbuf[INET6_ADDRSTRLEN];
|
2022-01-05 16:23:23 +01:00
|
|
|
bool use_star = false;
|
|
|
|
|
|
|
|
if (ea->fmt[0] == 's') {
|
|
|
|
use_star = true;
|
|
|
|
ea->fmt++;
|
|
|
|
}
|
2020-03-29 11:09:14 +02:00
|
|
|
|
2023-01-11 01:44:46 +01:00
|
|
|
if (!ipa || !ipa->ipa_type)
|
2021-03-26 19:14:24 +01:00
|
|
|
return bputs(buf, "(null)");
|
2021-03-01 21:41:30 +01:00
|
|
|
|
2022-01-05 16:23:23 +01:00
|
|
|
if (use_star) {
|
|
|
|
struct in_addr zero4 = {};
|
|
|
|
struct in6_addr zero6 = {};
|
|
|
|
|
|
|
|
switch (ipa->ipa_type) {
|
|
|
|
case IPADDR_V4:
|
|
|
|
if (!memcmp(&ipa->ip.addr, &zero4, sizeof(zero4)))
|
|
|
|
return bputch(buf, '*');
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPADDR_V6:
|
|
|
|
if (!memcmp(&ipa->ip.addr, &zero6, sizeof(zero6)))
|
|
|
|
return bputch(buf, '*');
|
|
|
|
break;
|
|
|
|
|
2023-01-30 16:06:29 +01:00
|
|
|
case IPADDR_NONE:
|
2022-01-05 16:23:23 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 22:52:23 +01:00
|
|
|
ipaddr2str(ipa, cbuf, sizeof(cbuf));
|
|
|
|
return bputs(buf, cbuf);
|
2020-03-29 11:09:14 +02:00
|
|
|
}
|
|
|
|
|
2022-01-14 11:56:25 +01:00
|
|
|
printfrr_ext_autoreg_p("I4", printfrr_i4);
|
2021-03-20 09:02:04 +01:00
|
|
|
static ssize_t printfrr_i4(struct fbuf *buf, struct printfrr_eargs *ea,
|
|
|
|
const void *ptr)
|
2019-05-14 16:28:31 +02:00
|
|
|
{
|
2021-02-18 22:52:23 +01:00
|
|
|
char cbuf[INET_ADDRSTRLEN];
|
2022-01-05 16:23:23 +01:00
|
|
|
bool use_star = false;
|
|
|
|
struct in_addr zero = {};
|
|
|
|
|
|
|
|
if (ea->fmt[0] == 's') {
|
|
|
|
use_star = true;
|
|
|
|
ea->fmt++;
|
|
|
|
}
|
2021-02-18 22:52:23 +01:00
|
|
|
|
|
|
|
if (!ptr)
|
2021-03-26 19:14:24 +01:00
|
|
|
return bputs(buf, "(null)");
|
2021-03-01 21:41:30 +01:00
|
|
|
|
2022-01-05 16:23:23 +01:00
|
|
|
if (use_star && !memcmp(ptr, &zero, sizeof(zero)))
|
|
|
|
return bputch(buf, '*');
|
|
|
|
|
2021-02-18 22:52:23 +01:00
|
|
|
inet_ntop(AF_INET, ptr, cbuf, sizeof(cbuf));
|
|
|
|
return bputs(buf, cbuf);
|
2019-05-14 16:28:31 +02:00
|
|
|
}
|
|
|
|
|
2022-01-14 11:56:25 +01:00
|
|
|
printfrr_ext_autoreg_p("I6", printfrr_i6);
|
2021-03-20 09:02:04 +01:00
|
|
|
static ssize_t printfrr_i6(struct fbuf *buf, struct printfrr_eargs *ea,
|
|
|
|
const void *ptr)
|
2019-05-14 16:28:31 +02:00
|
|
|
{
|
2021-02-18 22:52:23 +01:00
|
|
|
char cbuf[INET6_ADDRSTRLEN];
|
2022-01-05 16:23:23 +01:00
|
|
|
bool use_star = false;
|
|
|
|
struct in6_addr zero = {};
|
|
|
|
|
|
|
|
if (ea->fmt[0] == 's') {
|
|
|
|
use_star = true;
|
|
|
|
ea->fmt++;
|
|
|
|
}
|
2021-02-18 22:52:23 +01:00
|
|
|
|
|
|
|
if (!ptr)
|
2021-03-26 19:14:24 +01:00
|
|
|
return bputs(buf, "(null)");
|
2021-03-01 21:41:30 +01:00
|
|
|
|
2022-01-05 16:23:23 +01:00
|
|
|
if (use_star && !memcmp(ptr, &zero, sizeof(zero)))
|
|
|
|
return bputch(buf, '*');
|
|
|
|
|
2021-02-18 22:52:23 +01:00
|
|
|
inet_ntop(AF_INET6, ptr, cbuf, sizeof(cbuf));
|
|
|
|
return bputs(buf, cbuf);
|
2019-05-14 16:28:31 +02:00
|
|
|
}
|
|
|
|
|
2022-01-14 11:56:25 +01:00
|
|
|
printfrr_ext_autoreg_p("FX", printfrr_pfx);
|
2021-03-20 09:02:04 +01:00
|
|
|
static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea,
|
|
|
|
const void *ptr)
|
2019-05-14 16:28:31 +02:00
|
|
|
{
|
2022-03-11 11:59:38 +01:00
|
|
|
bool host_only = false;
|
|
|
|
|
|
|
|
if (ea->fmt[0] == 'h') {
|
|
|
|
ea->fmt++;
|
|
|
|
host_only = true;
|
|
|
|
}
|
2021-02-18 22:52:23 +01:00
|
|
|
|
|
|
|
if (!ptr)
|
2021-03-26 19:14:24 +01:00
|
|
|
return bputs(buf, "(null)");
|
2021-03-01 21:41:30 +01:00
|
|
|
|
2022-03-11 11:59:38 +01:00
|
|
|
if (host_only)
|
|
|
|
return prefixhost2str(buf, (struct prefix *)ptr);
|
|
|
|
else {
|
|
|
|
char cbuf[PREFIX_STRLEN];
|
|
|
|
|
|
|
|
prefix2str(ptr, cbuf, sizeof(cbuf));
|
|
|
|
return bputs(buf, cbuf);
|
|
|
|
}
|
2019-05-14 16:28:31 +02:00
|
|
|
}
|
|
|
|
|
2022-01-14 11:56:25 +01:00
|
|
|
printfrr_ext_autoreg_p("PSG4", printfrr_psg);
|
2021-03-20 09:02:04 +01:00
|
|
|
static ssize_t printfrr_psg(struct fbuf *buf, struct printfrr_eargs *ea,
|
|
|
|
const void *ptr)
|
2019-05-14 16:28:31 +02:00
|
|
|
{
|
|
|
|
const struct prefix_sg *sg = ptr;
|
2021-02-18 22:52:23 +01:00
|
|
|
ssize_t ret = 0;
|
2019-05-14 16:28:31 +02:00
|
|
|
|
2021-02-18 22:52:23 +01:00
|
|
|
if (!sg)
|
2021-03-26 19:14:24 +01:00
|
|
|
return bputs(buf, "(null)");
|
2021-03-01 21:41:30 +01:00
|
|
|
|
2021-02-18 22:52:23 +01:00
|
|
|
if (sg->src.s_addr == INADDR_ANY)
|
|
|
|
ret += bputs(buf, "(*,");
|
|
|
|
else
|
|
|
|
ret += bprintfrr(buf, "(%pI4,", &sg->src);
|
2021-03-01 21:41:30 +01:00
|
|
|
|
2021-02-18 22:52:23 +01:00
|
|
|
if (sg->grp.s_addr == INADDR_ANY)
|
|
|
|
ret += bputs(buf, "*)");
|
|
|
|
else
|
|
|
|
ret += bprintfrr(buf, "%pI4)", &sg->grp);
|
2019-05-14 16:28:31 +02:00
|
|
|
|
2021-02-18 22:52:23 +01:00
|
|
|
return ret;
|
2019-05-14 16:28:31 +02:00
|
|
|
}
|