From 781ddb4a7fff00922f2c7b7eb1d4dc03a1580432 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 12 Jan 2017 11:04:06 +0100 Subject: [PATCH 01/64] configure: add enable-evpn support By default, EVPN is disabled by default. In order to support it, the configure command has been made available in order to introduce a define that is used for compilation. Signed-off-by: Philippe Guibert --- configure.ac | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/configure.ac b/configure.ac index 1436b2fc7c..83250776f9 100755 --- a/configure.ac +++ b/configure.ac @@ -285,6 +285,8 @@ AC_ARG_ENABLE([protobuf], AS_HELP_STRING([--enable-protobuf], [Enable experimental protobuf support])) AC_ARG_ENABLE([oldvpn_commands], AS_HELP_STRING([--enable-old-vpn-commands], [Keep old vpn commands])) +AC_ARG_ENABLE(evpn, + AS_HELP_STRING([--enable-evpn], [enable EVPN support)])) AC_CHECK_HEADERS(json-c/json.h) AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c") @@ -397,6 +399,13 @@ if test "$enable_old_vpn_commands" = "yes"; then AC_DEFINE(KEEP_OLD_VPN_COMMANDS,, [Define for compiling with old vpn commands]) fi +# Logic for evpn support. +# +if test "$enable_evpn" = "yes"; then + have_evpn=yes + AC_DEFINE(HAVE_EVPN,, [Define for compiling with EVPN]) +fi + # Fail if the user explicity enabled protobuf support and we couldn't # find the compiler or libraries. if test "x$have_protobuf" = "xno" && test "x$enable_protobuf" = "xyes"; then From 924bf71cd1dab34afc51d3a1c4723da6a7cb24db Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 5 Dec 2016 14:11:07 +0100 Subject: [PATCH 02/64] lib: add AFI_L2VPN and SAFI_EVPN To support EVPN, a new AFI and SAFI value are defined here. For internal processing, two other values are used. Those values will be used to reach RIB entries by using internal afi and safi values as indexes. This commit is using naming convention for using EVPN. External value exchanged in BGP packets is called of with IANA_ presence in macro, while internal value will not have _IANA_ presence. Signed-off-by: Philippe Guibert --- lib/prefix.c | 4 ++++ lib/zebra.h | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index bc1c681058..f4012a5957 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -236,6 +236,8 @@ afi2str(afi_t afi) return "IPv6"; case AFI_ETHER: return "ethernet"; + case AFI_L2VPN: + return "l2vpn"; case AFI_MAX: return "bad-value"; default: @@ -256,6 +258,8 @@ safi2str(safi_t safi) return "encap"; case SAFI_MPLS_VPN: return "vpn"; + case SAFI_EVPN: + return "evpn"; } return NULL; } diff --git a/lib/zebra.h b/lib/zebra.h index 19a26b5230..db6fcf93ad 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -402,7 +402,8 @@ typedef enum { AFI_IP = 1, AFI_IP6 = 2, AFI_ETHER = 3, /* RFC 1700 has "6" for 802.* */ - AFI_MAX = 4 + AFI_L2VPN = 4, + AFI_MAX = 5 } afi_t; /* Subsequent Address Family Identifier. */ @@ -412,7 +413,8 @@ typedef enum { #define SAFI_RESERVED_4 4 #define SAFI_ENCAP 5 #define SAFI_RESERVED_5 5 -#define SAFI_MAX 6 +#define SAFI_EVPN 6 +#define SAFI_MAX 7 #define IANA_SAFI_RESERVED 0 #define IANA_SAFI_UNICAST 1 @@ -442,6 +444,7 @@ typedef enum { #define IANA_SAFI_UNICAST 1 #define IANA_SAFI_MULTICAST 2 #define IANA_SAFI_ENCAP 7 +#define IANA_SAFI_EVPN 70 #define IANA_SAFI_MPLS_VPN 128 /* Default Administrative Distance of each protocol. */ @@ -482,6 +485,8 @@ static inline afi_t afi_iana2int (iana_afi_t afi) return AFI_IP; if (afi == IANA_AFI_IPV6) return AFI_IP6; + if (afi == IANA_AFI_L2VPN) + return AFI_L2VPN; return AFI_MAX; } @@ -491,6 +496,8 @@ static inline iana_afi_t afi_int2iana (afi_t afi) return IANA_AFI_IPV4; if (afi == AFI_IP6) return IANA_AFI_IPV6; + if (afi == AFI_L2VPN) + return IANA_AFI_L2VPN; return IANA_AFI_RESERVED; } @@ -504,6 +511,8 @@ static inline safi_t safi_iana2int (safi_t safi) return SAFI_MPLS_VPN; if (safi == IANA_SAFI_ENCAP) return SAFI_ENCAP; + if (safi == IANA_SAFI_EVPN) + return SAFI_EVPN; return SAFI_MAX; } @@ -517,6 +526,8 @@ static inline safi_t safi_int2iana (safi_t safi) return IANA_SAFI_MPLS_VPN; if (safi == SAFI_ENCAP) return IANA_SAFI_ENCAP; + if (safi == SAFI_EVPN) + return IANA_SAFI_EVPN; return IANA_SAFI_RESERVED; } From a440846ea622ef4ac3ef681baff4c5331487b8f1 Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 27 Jul 2016 10:20:47 -0700 Subject: [PATCH 03/64] lib: EVPN prefix definition Extend the prefix data structure to allow for basic support for EVPN type-3 and type-2 routes. Note: This may be revised in future. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Ticket: CM-11937 Reviewed By: CCR-5001 Testing Done: None Signed-off-by: Philippe Guibert --- lib/prefix.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/prefix.h b/lib/prefix.h index eb69e98f04..b96a17cd08 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -47,6 +47,39 @@ struct ethaddr { } __packed; +/* length is the number of valuable bits of prefix structure +* 18 bytes is current length in structure, if address is ipv4 +* 30 bytes is in case of ipv6 +*/ +#define PREFIX_LEN_ROUTE_TYPE_5_IPV4 (18*8) +#define PREFIX_LEN_ROUTE_TYPE_5_IPV6 (30*8) + +/* EVPN address (RFC 7432) */ +struct evpn_addr +{ + u_char route_type; + u_char flags; +#define IP_ADDR_NONE 0x0 +#define IP_ADDR_V4 0x1 +#define IP_ADDR_V6 0x2 + struct ethaddr mac; + uint32_t eth_tag; + u_char ip_prefix_length; + union + { + struct in_addr v4_addr; + struct in6_addr v6_addr; + } ip; +}; + +/* EVPN prefix structure. */ +struct prefix_evpn +{ + u_char family; + u_char prefixlen; + struct evpn_addr prefix __attribute__ ((aligned (8))); +}; + /* * A struct prefix contains an address family, a prefix length, and an * address. This can represent either a 'network prefix' as defined @@ -83,6 +116,9 @@ struct prefix struct ethaddr prefix_eth; /* AF_ETHERNET */ u_char val[8]; uintptr_t ptr; +#if defined(HAVE_EVPN) + struct evpn_addr prefix_evpn; +#endif } u __attribute__ ((aligned (8))); }; From 4470c22cad9c6b928287e506788ed02b22e7854a Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 12 Jan 2017 10:14:18 +0100 Subject: [PATCH 04/64] lib: add prefix support for evpn route type 5 The requirement from draft-ietf-bess-evpn-prefix-advertisement-03 mentions that the Eth-Tag ID, IP Prefix Length and IP Prefix will be part of the route key used by BGP. The ip prefix length is then appended to the evpn_addr. In addition to this, the ethernet tag ID is reused. Signed-off-by: Philippe Guibert --- lib/prefix.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/prefix.h b/lib/prefix.h index b96a17cd08..4a66b79502 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -62,6 +62,8 @@ struct evpn_addr #define IP_ADDR_NONE 0x0 #define IP_ADDR_V4 0x1 #define IP_ADDR_V6 0x2 +#define IP_PREFIX_V4 0x4 +#define IP_PREFIX_V6 0x8 struct ethaddr mac; uint32_t eth_tag; u_char ip_prefix_length; From 79c0c959860d1773404a16f1fa62431ab333d2e0 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 27 Oct 2016 10:24:44 +0200 Subject: [PATCH 05/64] lib: afi_ether structure packing fix 'packed' keyword had no effect on packing the afi_ethernet structure. The attribute keyword has been eppended in order to take into account the packed feature. Signed-off-by: Julien Courtat --- lib/prefix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/prefix.h b/lib/prefix.h index 4a66b79502..1756dd21c8 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -44,7 +44,7 @@ */ struct ethaddr { u_char octet[ETHER_ADDR_LEN]; -} __packed; +} __attribute__ ((packed)); /* length is the number of valuable bits of prefix structure From 9e6df0b7ac03724397fb27472b745f6156d27152 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 4 Jan 2017 15:45:54 +0100 Subject: [PATCH 06/64] lib: define BGP_EVPN_NODE This define introduces bgp sub node address-family evpn. Signed-off-by: Philippe Guibert --- lib/command.c | 3 +++ lib/command.h | 1 + lib/vty.c | 1 + 3 files changed, 5 insertions(+) diff --git a/lib/command.c b/lib/command.c index b166d8e0da..24272ccd1e 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1055,6 +1055,7 @@ node_parent ( enum node_type node ) case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: + case BGP_EVPN_NODE: ret = BGP_NODE; break; case KEYCHAIN_KEY_NODE: @@ -1421,6 +1422,7 @@ cmd_exit (struct vty *vty) case BGP_VNC_L2_GROUP_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: + case BGP_EVPN_NODE: vty->node = BGP_NODE; break; case LDP_IPV4_NODE: @@ -1489,6 +1491,7 @@ DEFUN (config_end, case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: + case BGP_EVPN_NODE: case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: diff --git a/lib/command.h b/lib/command.h index 29283418ce..d62f7655ee 100644 --- a/lib/command.h +++ b/lib/command.h @@ -105,6 +105,7 @@ enum node_type BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */ BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */ RFP_DEFAULTS_NODE, /* RFP defaults node */ + BGP_EVPN_NODE, /* BGP EVPN node. */ OSPF_NODE, /* OSPF protocol mode */ OSPF6_NODE, /* OSPF protocol for IPv6 mode */ LDP_NODE, /* LDP protocol mode */ diff --git a/lib/vty.c b/lib/vty.c index ce6349bf77..3a3265f54d 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -750,6 +750,7 @@ vty_end_config (struct vty *vty) case BGP_IPV4M_NODE: case BGP_IPV6_NODE: case BGP_IPV6M_NODE: + case BGP_EVPN_NODE: case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: From 14a227b87345954bfa5c3cd60ece26ec7baf0f06 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 4 Jan 2017 15:47:00 +0100 Subject: [PATCH 07/64] vtysh: add support for bgp evpn address-family Add support for evpn address-family on vty shell. Signed-off-by: Philippe Guibert --- vtysh/vtysh.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 6427b8c165..255f2e873a 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -307,7 +307,7 @@ vtysh_execute_func (const char *line, int pager) || saved_node == BGP_ENCAP_NODE || saved_node == BGP_ENCAPV6_NODE || saved_node == BGP_IPV4_NODE || saved_node == BGP_IPV6_NODE || saved_node == BGP_IPV4M_NODE - || saved_node == BGP_IPV6M_NODE) + || saved_node == BGP_IPV6M_NODE || saved_node == BGP_EVPN_NODE) && (tried == 1)) { vtysh_execute("exit-address-family"); @@ -561,7 +561,8 @@ vtysh_mark_file (const char *filename) { if ((prev_node == BGP_VPNV4_NODE || prev_node == BGP_IPV4_NODE || prev_node == BGP_IPV6_NODE || prev_node == BGP_IPV4M_NODE - || prev_node == BGP_IPV6M_NODE || prev_node == BGP_VPNV6_NODE) + || prev_node == BGP_IPV6M_NODE || prev_node == BGP_VPNV6_NODE + || prev_node == BGP_EVPN_NODE) && (tried == 1)) { fprintf(stdout, "exit-address-family\n"); @@ -956,6 +957,12 @@ static struct cmd_node bgp_ipv6m_node = "%s(config-router-af)# " }; +static struct cmd_node bgp_evpn_node = +{ + BGP_EVPN_NODE, + "%s(config-router-af)# " +}; + static struct cmd_node bgp_vnc_defaults_node = { BGP_VNC_DEFAULTS_NODE, @@ -1203,6 +1210,20 @@ DEFUNSH (VTYSH_BGPD, return CMD_SUCCESS; } +DEFUNSH (VTYSH_BGPD, + address_family_evpn, + address_family_evpn_cmd, + "address-family evpn", + "Enter Address Family command mode\n" + "Enter Address Family command mode\n" + "Address family\n") +{ +#if defined(HAVE_EVPN) + vty->node = BGP_EVPN_NODE; +#endif /* HAVE_EVPN */ + return CMD_SUCCESS; +} + #if defined (ENABLE_BGP_VNC) DEFUNSH (VTYSH_BGPD, vnc_defaults, @@ -1511,6 +1532,7 @@ vtysh_exit (struct vty *vty) case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case BGP_VRF_POLICY_NODE: + case BGP_EVPN_NODE: case BGP_VNC_DEFAULTS_NODE: case BGP_VNC_NVE_GROUP_NODE: case BGP_VNC_L2_GROUP_NODE: @@ -3114,6 +3136,7 @@ vtysh_init_vty (void) install_node (&bgp_ipv6_node, NULL); install_node (&bgp_ipv6m_node, NULL); install_node (&bgp_vrf_policy_node, NULL); + install_node (&bgp_evpn_node, NULL); install_node (&bgp_vnc_defaults_node, NULL); install_node (&bgp_vnc_nve_group_node, NULL); install_node (&bgp_vnc_l2_group_node, NULL); @@ -3150,6 +3173,7 @@ vtysh_init_vty (void) vtysh_install_default (BGP_IPV4M_NODE); vtysh_install_default (BGP_IPV6_NODE); vtysh_install_default (BGP_IPV6M_NODE); + vtysh_install_default (BGP_EVPN_NODE); #if ENABLE_BGP_VNC vtysh_install_default (BGP_VRF_POLICY_NODE); vtysh_install_default (BGP_VNC_DEFAULTS_NODE); @@ -3222,6 +3246,7 @@ vtysh_init_vty (void) install_element (BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd); install_element (BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd); + install_element (BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd); #if defined (ENABLE_BGP_VNC) install_element (BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd); install_element (BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd); @@ -3267,6 +3292,7 @@ vtysh_init_vty (void) install_element (BGP_IPV6_NODE, &vtysh_end_all_cmd); install_element (BGP_IPV6M_NODE, &vtysh_end_all_cmd); install_element (BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd); + install_element (BGP_EVPN_NODE, &vtysh_end_all_cmd); install_element (BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd); install_element (BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd); install_element (BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd); @@ -3322,6 +3348,7 @@ vtysh_init_vty (void) #endif install_element (BGP_NODE, &address_family_ipv4_unicast_cmd); install_element (BGP_NODE, &address_family_ipv6_cmd); + install_element (BGP_NODE, &address_family_evpn_cmd); install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); install_element (BGP_ENCAP_NODE, &exit_address_family_cmd); @@ -3330,6 +3357,7 @@ vtysh_init_vty (void) install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); install_element (BGP_IPV6_NODE, &exit_address_family_cmd); install_element (BGP_IPV6M_NODE, &exit_address_family_cmd); + install_element (BGP_EVPN_NODE, &exit_address_family_cmd); install_element (BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd); install_element (BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd); From 4e0b7b6d35ff451872492546a1cf0e5536cd4b28 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 5 Sep 2016 10:54:06 +0200 Subject: [PATCH 08/64] bgpd: basic vty support for EVPN Introduction of EVPN address-family node that is reachable under BGP node, like follow: address-family evpn. Under that node, only some commands are available for configuring a neighbor or setting some basic settings like attribute unchanged behaviour. Currently, no vty command is available for setting NLRI entries for EVPN. Signed-off-by: Philippe Guibert --- bgpd/bgp_vty.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index b4425297b3..cca34d0a85 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -74,6 +74,9 @@ bgp_node_afi (struct vty *vty) case BGP_ENCAPV6_NODE: afi = AFI_IP6; break; + case BGP_EVPN_NODE: + afi = AFI_L2VPN; + break; default: afi = AFI_IP; break; @@ -101,6 +104,9 @@ bgp_node_safi (struct vty *vty) case BGP_IPV6M_NODE: safi = SAFI_MULTICAST; break; + case BGP_EVPN_NODE: + safi = SAFI_EVPN; + break; default: safi = SAFI_UNICAST; break; @@ -119,6 +125,9 @@ bgp_vty_afi_from_arg(const char *afi_str) else if (!strcmp(afi_str, "ipv6")) { afi = AFI_IP6; } + else if (!strcmp(afi_str, "l2vpn")) { + afi = AFI_L2VPN; + } return afi; } @@ -195,6 +204,12 @@ argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t if (safi) *safi = SAFI_ENCAP; } + else if (argv_find (argv, argc, "evpn", index)) + { + ret = 1; + if (safi) + *safi = SAFI_EVPN; + } return ret; } @@ -5695,6 +5710,18 @@ DEFUN (address_family_encapv6, return CMD_SUCCESS; } +DEFUN (address_family_evpn, + address_family_evpn_cmd, + "address-family evpn", + "Enter Address Family command mode\n" + "Address family\n") +{ +#if defined(HAVE_EVPN) + vty->node = BGP_EVPN_NODE; +#endif /* HAVE_EVPN */ + return CMD_SUCCESS; +} + DEFUN (exit_address_family, exit_address_family_cmd, "exit-address-family", @@ -5707,7 +5734,8 @@ DEFUN (exit_address_family, || vty->node == BGP_IPV6M_NODE || vty->node == BGP_VPNV6_NODE || vty->node == BGP_ENCAP_NODE - || vty->node == BGP_ENCAPV6_NODE) + || vty->node == BGP_ENCAPV6_NODE + || vty->node == BGP_EVPN_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } @@ -9966,6 +9994,13 @@ static struct cmd_node bgp_encapv6_node = 1 }; +static struct cmd_node bgp_evpn_node = +{ + BGP_EVPN_NODE, + "%s(config-router-evpn)# ", + 1 +}; + static void community_list_vty (void); void @@ -9981,6 +10016,7 @@ bgp_vty_init (void) install_node (&bgp_vpnv6_node, NULL); install_node (&bgp_encap_node, NULL); install_node (&bgp_encapv6_node, NULL); + install_node (&bgp_evpn_node, NULL); /* Install default VTY commands to new nodes. */ install_default (BGP_NODE); @@ -9992,6 +10028,7 @@ bgp_vty_init (void) install_default (BGP_VPNV6_NODE); install_default (BGP_ENCAP_NODE); install_default (BGP_ENCAPV6_NODE); + install_default (BGP_EVPN_NODE); /* "bgp multiple-instance" commands. */ install_element (CONFIG_NODE, &bgp_multiple_instance_cmd); @@ -10205,6 +10242,7 @@ bgp_vty_init (void) install_element (BGP_VPNV6_NODE, &neighbor_activate_cmd); install_element (BGP_ENCAP_NODE, &neighbor_activate_cmd); install_element (BGP_ENCAPV6_NODE, &neighbor_activate_cmd); + install_element (BGP_EVPN_NODE, &neighbor_activate_cmd); /* "no neighbor activate" commands. */ install_element (BGP_NODE, &no_neighbor_activate_cmd); @@ -10216,6 +10254,7 @@ bgp_vty_init (void) install_element (BGP_VPNV6_NODE, &no_neighbor_activate_cmd); install_element (BGP_ENCAP_NODE, &no_neighbor_activate_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_activate_cmd); + install_element (BGP_EVPN_NODE, &no_neighbor_activate_cmd); /* "neighbor peer-group" set commands. * Long term we should only accept this command under BGP_NODE and not all of @@ -10286,6 +10325,9 @@ bgp_vty_init (void) install_element (BGP_ENCAPV6_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_ENCAPV6_NODE, &no_neighbor_attr_unchanged_cmd); + install_element (BGP_EVPN_NODE, &neighbor_attr_unchanged_cmd); + install_element (BGP_EVPN_NODE, &no_neighbor_attr_unchanged_cmd); + /* "nexthop-local unchanged" commands */ install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd); @@ -10828,6 +10870,8 @@ bgp_vty_init (void) install_element (BGP_NODE, &address_family_encap_cmd); install_element (BGP_NODE, &address_family_encapv6_cmd); + install_element (BGP_NODE, &address_family_evpn_cmd); + /* "exit-address-family" command. */ install_element (BGP_IPV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); @@ -10837,6 +10881,7 @@ bgp_vty_init (void) install_element (BGP_VPNV6_NODE, &exit_address_family_cmd); install_element (BGP_ENCAP_NODE, &exit_address_family_cmd); install_element (BGP_ENCAPV6_NODE, &exit_address_family_cmd); + install_element (BGP_EVPN_NODE, &exit_address_family_cmd); /* "clear ip bgp commands" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd); From 3d6c0dfa8782065252aef2397e313ac1979bb7b0 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 5 Sep 2016 10:53:51 +0200 Subject: [PATCH 09/64] bgpd: basic support for EVPN To handle BGP NLRI EVPN messages, bgp is modified to handle AFI_L2VPN and SAFI_EVPN values. Signed-off-by: Philippe Guibert --- bgpd/bgp_open.c | 15 +++++- bgpd/bgp_packet.c | 4 +- bgpd/bgp_route.c | 111 +++++++++++++++++++++++++----------------- bgpd/bgp_updgrp_adv.c | 4 +- bgpd/bgp_vty.c | 4 ++ bgpd/bgpd.c | 11 ++++- 6 files changed, 99 insertions(+), 50 deletions(-) diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 7dbb439be1..51079f31e0 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -93,6 +93,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso case AFI_IP6: json_object_string_add(json_cap, "capabilityErrorMultiProtocolAfi", "IPv6"); break; + case AFI_L2VPN: + json_object_string_add(json_cap, "capabilityErrorMultiProtocolAfi", "L2VPN"); + break; default: json_object_int_add(json_cap, "capabilityErrorMultiProtocolAfiUnknown", ntohs (mpc.afi)); break; @@ -111,6 +114,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso case SAFI_ENCAP: json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "encap"); break; + case SAFI_EVPN: + json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "EVPN"); + break; default: json_object_int_add(json_cap, "capabilityErrorMultiProtocolSafiUnknown", mpc.safi); break; @@ -127,6 +133,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso case AFI_IP6: vty_out (vty, "AFI IPv6, "); break; + case AFI_L2VPN: + vty_out (vty, "AFI L2VPN, "); + break; default: vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi)); break; @@ -145,6 +154,9 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, jso case SAFI_ENCAP: vty_out (vty, "SAFI ENCAP"); break; + case SAFI_EVPN: + vty_out (vty, "SAFI EVPN"); + break; default: vty_out (vty, "SAFI Unknown %d ", mpc.safi); break; @@ -1136,7 +1148,8 @@ bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] - && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP]) + && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP] + && ! peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) { zlog_err ("%s [Error] Configured AFI/SAFIs do not " "overlap with received MP capabilities", diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 2df22ab568..c7453509fa 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -246,13 +246,13 @@ bgp_write_packet (struct peer *peer) if (!(PAF_SUBGRP(paf))->t_coalesce && peer->afc_nego[afi][safi] && peer->synctime && ! CHECK_FLAG (peer->af_sflags[afi][safi], - PEER_STATUS_EOR_SEND)) + PEER_STATUS_EOR_SEND) + && safi != SAFI_EVPN) { SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND); return bgp_update_packet_eor (peer, afi, safi); } - } continue; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0123ed17ea..84c0ee1021 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -84,7 +84,8 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix if (!table) return NULL; - if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || + (safi == SAFI_EVPN)) { prn = bgp_node_get (table, (struct prefix *) prd); @@ -97,7 +98,8 @@ bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix rn = bgp_node_get (table, p); - if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || + (safi == SAFI_EVPN)) rn->prn = prn; return rn; @@ -3067,7 +3069,7 @@ bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi) if (peer->status != Established) return; - if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)) + if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP) && (safi != SAFI_EVPN)) bgp_soft_reconfig_table (peer, afi, safi, NULL, NULL); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; @@ -3288,7 +3290,7 @@ bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi) if (!peer->clear_node_queue->thread) peer_lock (peer); - if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP) + if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP && safi != SAFI_EVPN) bgp_clear_route_table (peer, afi, safi, NULL); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; @@ -3421,40 +3423,56 @@ void bgp_cleanup_routes (struct bgp *bgp) { afi_t afi; + struct bgp_node *rn; for (afi = AFI_IP; afi < AFI_MAX; ++afi) { - struct bgp_node *rn; - + if (afi == AFI_L2VPN) + continue; bgp_cleanup_table(bgp->rib[afi][SAFI_UNICAST], SAFI_UNICAST); - /* - * VPN and ENCAP tables are two-level (RD is top level) + * VPN and ENCAP and EVPN tables are two-level (RD is top level) */ - for (rn = bgp_table_top(bgp->rib[afi][SAFI_MPLS_VPN]); rn; - rn = bgp_route_next (rn)) - { - if (rn->info) - { - bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_MPLS_VPN); - bgp_table_finish ((struct bgp_table **)&(rn->info)); - rn->info = NULL; - bgp_unlock_node(rn); - } - } - - for (rn = bgp_table_top(bgp->rib[afi][SAFI_ENCAP]); rn; - rn = bgp_route_next (rn)) - { - if (rn->info) - { - bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_ENCAP); - bgp_table_finish ((struct bgp_table **)&(rn->info)); - rn->info = NULL; - bgp_unlock_node(rn); - } + if (afi != AFI_L2VPN) + { + safi_t safi; + safi = SAFI_MPLS_VPN; + for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; + rn = bgp_route_next (rn)) + { + if (rn->info) + { + bgp_cleanup_table((struct bgp_table *)(rn->info), safi); + bgp_table_finish ((struct bgp_table **)&(rn->info)); + rn->info = NULL; + bgp_unlock_node(rn); + } + } + safi = SAFI_ENCAP; + for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; + rn = bgp_route_next (rn)) + { + if (rn->info) + { + bgp_cleanup_table((struct bgp_table *)(rn->info), safi); + bgp_table_finish ((struct bgp_table **)&(rn->info)); + rn->info = NULL; + bgp_unlock_node(rn); + } + } } } + for (rn = bgp_table_top(bgp->rib[AFI_L2VPN][SAFI_EVPN]); rn; + rn = bgp_route_next (rn)) + { + if (rn->info) + { + bgp_cleanup_table((struct bgp_table *)(rn->info), SAFI_EVPN); + bgp_table_finish ((struct bgp_table **)&(rn->info)); + rn->info = NULL; + bgp_unlock_node(rn); + } + } } void @@ -4209,7 +4227,7 @@ bgp_static_add (struct bgp *bgp) for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) { - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN)) { table = rn->info; @@ -4243,7 +4261,7 @@ bgp_static_delete (struct bgp *bgp) for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) { - if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN)) { table = rn->info; @@ -5099,7 +5117,7 @@ bgp_aggregate_increment (struct bgp *bgp, struct prefix *p, struct bgp_table *table; /* MPLS-VPN aggregation is not yet supported. */ - if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi = SAFI_EVPN)) return; table = bgp->aggregate[afi][safi]; @@ -5136,7 +5154,7 @@ bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p, struct bgp_table *table; /* MPLS-VPN aggregation is not yet supported. */ - if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi = SAFI_EVPN)) return; table = bgp->aggregate[afi][safi]; @@ -5924,7 +5942,7 @@ route_vty_out (struct vty *vty, struct prefix *p, * neccessarily the same as the prefix address family. * Both SAFI_MPLS_VPN and SAFI_ENCAP use the MP nexthop field */ - if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN)) + if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN) || (safi = SAFI_EVPN)) { if (attr->extra) { @@ -5956,7 +5974,7 @@ route_vty_out (struct vty *vty, struct prefix *p, { json_nexthop_global = json_object_new_object(); - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi = SAFI_EVPN)) json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in)); else json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->nexthop)); @@ -5966,7 +5984,7 @@ route_vty_out (struct vty *vty, struct prefix *p, } else { - if (safi == SAFI_MPLS_VPN) + if ((safi == SAFI_MPLS_VPN) || (safi = SAFI_EVPN)) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else @@ -6180,9 +6198,10 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t if (p->family == AF_INET && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || + safi == SAFI_EVPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) json_object_string_add(json_net, "nextHop", inet_ntoa (attr->extra->mp_nexthop_global_in)); else json_object_string_add(json_net, "nextHop", inet_ntoa (attr->nexthop)); @@ -6218,9 +6237,10 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t if (p->family == AF_INET && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || + safi == SAFI_EVPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else @@ -6307,7 +6327,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, if (p->family == AF_INET && (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { if (json) json_object_string_add(json_out, "mpNexthopGlobalIn", inet_ntoa (attr->extra->mp_nexthop_global_in)); @@ -6717,9 +6737,10 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (p->family == AF_INET && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || + safi == SAFI_EVPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { if (json_paths) json_object_string_add(json_nexthop_global, "ip", inet_ntoa (attr->extra->mp_nexthop_global_in)); @@ -7657,9 +7678,9 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, else { vty_out (vty, "BGP routing table entry for %s%s%s/%d%s", - ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) ? + ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) ? prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), - safi == SAFI_MPLS_VPN ? ":" : "", + ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":" : "", inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN), p->prefixlen, VTY_NEWLINE); } @@ -7779,7 +7800,7 @@ bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, json_paths = json_object_new_array(); } - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn)) { @@ -10054,7 +10075,7 @@ bgp_clear_damp_route (struct vty *vty, const char *view_name, match.family = afi2family (afi); - if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN)) { for (rn = bgp_table_top (bgp->rib[AFI_IP][safi]); rn; rn = bgp_route_next (rn)) { diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 48f56a29b2..efb2046e12 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -605,6 +605,7 @@ subgroup_announce_table (struct update_subgroup *subgrp, if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP + && safi != SAFI_EVPN && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) subgroup_default_originate (subgrp, 0); @@ -668,7 +669,8 @@ subgroup_announce_route (struct update_subgroup *subgrp) return; if (SUBGRP_SAFI (subgrp) != SAFI_MPLS_VPN && - SUBGRP_SAFI (subgrp) != SAFI_ENCAP) + SUBGRP_SAFI (subgrp) != SAFI_ENCAP && + SUBGRP_SAFI (subgrp) != SAFI_EVPN) subgroup_announce_table (subgrp, NULL); else for (rn = bgp_table_top (update_subgroup_rib (subgrp)); rn; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index cca34d0a85..881173d382 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6834,6 +6834,8 @@ afi_safi_print (afi_t afi, safi_t safi) return "IPv6 VPN"; else if (afi == AFI_IP6 && safi == SAFI_ENCAP) return "IPv6 Encap"; + else if (afi == AFI_L2VPN && safi == SAFI_EVPN) + return "L2VPN EVPN"; else return "Unknown"; } @@ -6857,6 +6859,8 @@ afi_safi_json (afi_t afi, safi_t safi) return "IPv6VPN"; else if (afi == AFI_IP6 && safi == SAFI_ENCAP) return "IPv6Encap"; + else if (afi == AFI_L2VPN && safi == SAFI_EVPN) + return "L2VPN EVPN"; else return "Unknown"; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index fc6968e9d9..1cad7c5a15 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1643,6 +1643,8 @@ peer_as_change (struct peer *peer, as_t as, int as_specified) PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG (peer->af_flags[AFI_L2VPN][SAFI_EVPN], + PEER_FLAG_REFLECTOR_CLIENT); } /* local-as reset */ @@ -7217,7 +7219,11 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi, else if (safi == SAFI_ENCAP) vty_out (vty, "ipv6 encap"); } - + else if (afi == AFI_L2VPN) + { + if (safi == SAFI_EVPN) + vty_out (vty, "evpn"); + } vty_out (vty, "%s", VTY_NEWLINE); *write = 1; @@ -7518,6 +7524,9 @@ bgp_config_write (struct vty *vty) /* ENCAPv6 configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_ENCAP); + /* EVPN configuration. */ + write += bgp_config_write_family (vty, bgp, AFI_L2VPN, SAFI_EVPN); + #if ENABLE_BGP_VNC write += bgp_rfapi_cfg_write(vty, bgp); #endif From 2c9ba7c7cdbabedb618c4f6c5945a74dac81bd93 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 20 Jan 2017 17:13:24 +0100 Subject: [PATCH 10/64] bgpd: add support for epvn into afindex afindex needs knowledge of l2vpn afi parameter, as well as evpn safi parameter. Signed-off-by: Vivek Venkatraman --- bgpd/bgpd.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 2eef04e1d1..09c64aa331 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -73,6 +73,7 @@ enum bgp_af_index BGP_AF_IPV6_VPN, BGP_AF_IPV4_ENCAP, BGP_AF_IPV6_ENCAP, + BGP_AF_L2VPN_EVPN, BGP_AF_MAX }; @@ -1414,6 +1415,16 @@ afindex (afi_t afi, safi_t safi) break; } break; + case AFI_L2VPN: + switch (safi) + { + case SAFI_EVPN: + return BGP_AF_L2VPN_EVPN; + break; + default: + return BGP_AF_MAX; + break; + } default: return BGP_AF_MAX; break; From 212f5cbcedd477a4652a880f86eddd3b304ea7e5 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 26 Oct 2016 12:21:53 +0200 Subject: [PATCH 11/64] bgpd: enhance structures and esi and mac functions to handle EVPN EVPN introduces new objects to be handled: Ethernet Segment Identifier, and MAC Address. For Route type 5 message, it also involves gateway IP field that can be either IPv4 or IPv6 address. This commit introduces those main structures. It also introduces some functions to convert esi and mac address to string, and vice-versa. Signed-off-by: Philippe Guibert --- bgpd/Makefile.am | 4 +- bgpd/bgp_attr_evpn.c | 262 +++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_attr_evpn.h | 55 +++++++++ 3 files changed, 319 insertions(+), 2 deletions(-) create mode 100644 bgpd/bgp_attr_evpn.c create mode 100644 bgpd/bgp_attr_evpn.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 611dbb8558..4fda7adaab 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -79,7 +79,7 @@ libbgp_a_SOURCES = \ bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ - bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) + bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c noinst_HEADERS = \ bgp_memory.h \ @@ -90,7 +90,7 @@ noinst_HEADERS = \ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \ - $(BGP_VNC_RFAPI_HD) + $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c new file mode 100644 index 0000000000..8715062bae --- /dev/null +++ b/bgpd/bgp_attr_evpn.c @@ -0,0 +1,262 @@ +/* Ethernet-VPN Attribute handling file + Copyright (C) 2016 6WIND + +This file is part of Free Range Routing. + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include + +#include "command.h" +#include "prefix.h" +#include "log.h" +#include "memory.h" +#include "stream.h" + +#include "bgpd/bgp_attr_evpn.h" + +static uint8_t convertchartohexa (uint8_t *hexa, int *error) +{ + if( (*hexa == '0') || (*hexa == '1') || (*hexa == '2') || + (*hexa == '3') || (*hexa == '4') || (*hexa == '5') || + (*hexa == '6') || (*hexa == '7') || (*hexa == '8') || + (*hexa == '9')) + return (uint8_t)(*hexa)-'0'; + if((*hexa == 'a') || (*hexa == 'A')) + return 0xa; + if((*hexa == 'b') || (*hexa == 'B')) + return 0xb; + if((*hexa == 'c') || (*hexa == 'C')) + return 0xc; + if((*hexa == 'd') || (*hexa == 'D')) + return 0xd; + if((*hexa == 'e') || (*hexa == 'E')) + return 0xe; + if((*hexa == 'f') || (*hexa == 'F')) + return 0xf; + *error = -1; + return 0; +} + +/* 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 + */ +int +str2mac (const char *str, char *mac) +{ + unsigned int k=0, i, j; + uint8_t *ptr, *ptr2; + size_t len; + uint8_t car; + + if (!str) + return 0; + + if (str[0] == ':' && str[1] == '\0') + return 1; + + i = 0; + ptr = (uint8_t *)str; + while (i < 6) + { + uint8_t temp[5]; + int error = 0; + ptr2 = (uint8_t *)strchr((const char *)ptr, ':'); + if (ptr2 == NULL) + { + /* if last occurence return ok */ + if(i != 5) + { + zlog_err("[%s]: format non recognized",mac); + return 0; + } + len = strlen((char *)ptr); + } + else + { + len = ptr2 - ptr; + } + if(len > 5) + { + zlog_err("[%s]: format non recognized",mac); + return 0; + } + memcpy(temp, ptr, len); + for(j=0;j< len;j++) + { + if (k >= MAC_LEN) + return 0; + if(mac) + mac[k] = 0; + car = convertchartohexa (&temp[j], &error); + if (error) + return 0; + if(mac) + mac[k] = car << 4; + j++; + if(j == len) + return 0; + car = convertchartohexa (&temp[j], &error) & 0xf; + if (error) + return 0; + if(mac) + mac[k] |= car & 0xf; + k++; + i++; + } + ptr = ptr2; + if(ptr == NULL) + break; + ptr++; + } + if(mac && 0) + { + zlog_err("leave correct : %02x:%02x:%02x:%02x:%02x:%02x", + mac[0] & 0xff, mac[1] & 0xff, mac[2] & 0xff, + mac[3] & 0xff, mac[4] & 0xff, mac[5] & 0xff); + } + return 1; +} + +/* converts to an esi + * returns 1 on success, 0 otherwise + * format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ + * if id is null, check only is done + */ +int +str2esi (const char *str, struct eth_segment_id *id) +{ + unsigned int k=0, i, j; + uint8_t *ptr, *ptr2; + size_t len; + uint8_t car; + + if (!str) + return 0; + if (str[0] == ':' && str[1] == '\0') + return 1; + + i = 0; + ptr = (uint8_t *)str; + while (i < 10) + { + uint8_t temp[5]; + int error = 0; + ptr2 = (uint8_t *)strchr((const char *)ptr, ':'); + if (ptr2 == NULL) + { + /* if last occurence return ok */ + if(i != 9) + { + zlog_err("[%s]: format non recognized",str); + return 0; + } + len = strlen((char *)ptr); + } + else + { + len = ptr2 - ptr; + } + memcpy(temp, ptr, len); + if(len > 5) + { + zlog_err("[%s]: format non recognized",str); + return 0; + } + for(j=0;j< len;j++) + { + if (k >= ESI_LEN) + return 0; + if(id) + id->val[k] = 0; + car = convertchartohexa (&temp[j], &error); + if (error) + return 0; + if(id) + id->val[k] = car << 4; + j++; + if(j == len) + return 0; + car = convertchartohexa (&temp[j], &error) & 0xf; + if (error) + return 0; + if(id) + id->val[k] |= car & 0xf; + k++; + i++; + } + ptr = ptr2; + if(ptr == NULL) + break; + ptr++; + } + if(id && 0) + { + zlog_err("leave correct : %02x:%02x:%02x:%02x:%02x", + id->val[0], id->val[1], id->val[2], id->val[3], id->val[4]); + zlog_err("%02x:%02x:%02x:%02x:%02x", + id->val[5], id->val[6], id->val[7], id->val[8], id->val[9]); + } + return 1; +} + +char * +esi2str (struct eth_segment_id *id) +{ + char *ptr; + u_char *val; + + if(!id) + return NULL; + + val = id->val; + ptr = (char *) malloc ((ESI_LEN*2+ESI_LEN-1+1)*sizeof(char)); + + snprintf (ptr, (ESI_LEN*2+ESI_LEN-1+1), + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + val[0], val[1], val[2], val[3], val[4], + val[5], val[6], val[7], val[8], val[9]); + + return ptr; +} + +char * +mac2str (char *mac) +{ + char *ptr; + + if(!mac) + return NULL; + + ptr = (char *) malloc ((MAC_LEN*2+MAC_LEN-1+1)*sizeof(char)); + + snprintf (ptr, (MAC_LEN*2+MAC_LEN-1+1), "%02x:%02x:%02x:%02x:%02x:%02x", + (uint8_t) mac[0], (uint8_t)mac[1], (uint8_t)mac[2], (uint8_t)mac[3], + (uint8_t)mac[4], (uint8_t)mac[5]); + + return ptr; +} + +char *ecom_mac2str(char *ecom_mac) +{ + char *en; + + en = ecom_mac; + en+=2; + return mac2str(en); +} diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h new file mode 100644 index 0000000000..14846ebc1f --- /dev/null +++ b/bgpd/bgp_attr_evpn.h @@ -0,0 +1,55 @@ +/* E-VPN attribute handling structure file + Copyright (C) 2016 6WIND + +This file is part of Free Range Routing. + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _QUAGGA_BGP_ATTR_EVPN_H +#define _QUAGGA_BGP_ATTR_EVPN_H + +/* value of first byte of ESI */ +#define ESI_TYPE_ARBITRARY 0 /* */ +#define ESI_TYPE_LACP 1 /* <> */ +#define ESI_TYPE_BRIDGE 2 /* ::00 */ +#define ESI_TYPE_MAC 3 /* : */ +#define ESI_TYPE_ROUTER 4 /* : */ +#define ESI_TYPE_AS 5 /* : */ +#define MAX_ESI {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff} +#define ESI_LEN 10 + +#define MAX_ET 0xffffffff +u_long eth_tag_id; + +struct eth_segment_id +{ + u_char val[ESI_LEN]; +}; + +#define MAC_LEN 6 + +union gw_addr { + struct in_addr ipv4; + struct in6_addr ipv6; +}; + +extern int str2esi (const char *str, struct eth_segment_id *id); +extern int str2mac (const char *str, char *mac); +extern char *esi2str (struct eth_segment_id *id); +extern char *mac2str (char *mac); +extern char *ecom_mac2str(char *ecom_mac); + +#endif /* _QUAGGA_BGP_ATTR_EVPN_H */ From 7ef5a2328817de75095b625972562b540334a691 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 5 Sep 2016 11:07:25 +0200 Subject: [PATCH 12/64] bgpd: handling EVPN Route Type 5 NLRI message This patch introduces code to receive a NLRI message with route type 5, as defined in draft-ietf-bess-evpn-prefix-advertisement-02. It It increases the number of parameters to extract from the NLRI and to store into bgp extra information structure. Those parameters are the ESI (ethernet segment identifier), the gateway IP Address (which acts like nexthop attribute but is contained inside the NLRI itself) and the ethernet tag identifier ( that acts for the VXLan Identifier) This patch updates bgp_update() and bgp_withdraw() api, and then does the necessary adapations for rfapi. Signed-off-by: Philippe Guibert --- bgpd/Makefile.am | 5 +- bgpd/bgp_attr_evpn.c | 1 + bgpd/bgp_attr_evpn.h | 6 ++ bgpd/bgp_encap.c | 4 +- bgpd/bgp_evpn.c | 189 ++++++++++++++++++++++++++++++++++++ bgpd/bgp_evpn.h | 36 +++++++ bgpd/bgp_mplsvpn.c | 4 +- bgpd/bgp_packet.c | 20 ++-- bgpd/bgp_packet.h | 2 +- bgpd/bgp_route.c | 10 +- bgpd/bgp_route.h | 8 +- bgpd/bgpd.c | 1 + bgpd/rfapi/vnc_export_bgp.c | 32 +++--- 13 files changed, 280 insertions(+), 38 deletions(-) create mode 100644 bgpd/bgp_evpn.c create mode 100644 bgpd/bgp_evpn.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 4fda7adaab..4ce2cd03b5 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -79,7 +79,8 @@ libbgp_a_SOURCES = \ bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ - bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c + bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \ + bgp_evpn.c noinst_HEADERS = \ bgp_memory.h \ @@ -90,7 +91,7 @@ noinst_HEADERS = \ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \ - $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h + $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 8715062bae..76c0e51198 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -21,6 +21,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include #include "command.h" +#include "filter.h" #include "prefix.h" #include "log.h" #include "memory.h" diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 14846ebc1f..1e8ad3801c 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -46,6 +46,12 @@ union gw_addr { struct in6_addr ipv6; }; +struct bgp_route_evpn +{ + struct eth_segment_id eth_s_id; + union gw_addr gw_ip; +}; + extern int str2esi (const char *str, struct eth_segment_id *id); extern int str2mac (const char *str, char *mac); extern char *esi2str (struct eth_segment_id *id); diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c index 4ec45108b4..72a30220ff 100644 --- a/bgpd/bgp_encap.c +++ b/bgpd/bgp_encap.c @@ -188,10 +188,10 @@ bgp_nlri_parse_encap( if (attr) { bgp_update (peer, &p, 0, attr, afi, SAFI_ENCAP, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, NULL); } else { bgp_withdraw (peer, &p, 0, attr, afi, SAFI_ENCAP, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, NULL); } } diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c new file mode 100644 index 0000000000..fd785b9a64 --- /dev/null +++ b/bgpd/bgp_evpn.c @@ -0,0 +1,189 @@ +/* Ethernet-VPN Packet and vty Processing File + Copyright (C) 2016 6WIND + +This file is part of Free Range Routing. + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +#include + +#include "command.h" +#include "filter.h" +#include "prefix.h" +#include "log.h" +#include "memory.h" +#include "stream.h" + +#include "bgpd/bgp_attr_evpn.h" +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_evpn.h" + +int +bgp_nlri_parse_evpn (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw) +{ + u_char *pnt; + u_char *lim; + struct prefix p; + struct prefix_rd prd; + struct evpn_addr *p_evpn_p; + struct bgp_route_evpn evpn; + uint8_t route_type, route_length; + u_char *pnt_label; + u_int32_t addpath_id = 0; + + /* Check peer status. */ + if (peer->status != Established) + return 0; + + /* Make prefix_rd */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; + +#if !defined(HAVE_EVPN) + return -1; +#endif /* HAVE_EVPN */ + + p_evpn_p = &p.u.prefix_evpn; + pnt = packet->nlri; + lim = pnt + packet->length; + while (pnt < lim) + { + /* clear evpn structure */ + memset (&evpn, 0, sizeof (evpn)); + + /* Clear prefix structure. */ + memset (&p, 0, sizeof (struct prefix)); + memset(&evpn.gw_ip, 0, sizeof(union gw_addr)); + memset(&evpn.eth_s_id, 0, sizeof(struct eth_segment_id)); + + /* Fetch Route Type */ + route_type = *pnt++; + route_length = *pnt++; + /* simply ignore. goto next route type if any */ + if(route_type != EVPN_IP_PREFIX) + { + if (pnt + route_length > lim) + { + zlog_err ("not enough bytes for New Route Type left in NLRI?"); + return -1; + } + pnt += route_length; + continue; + } + + /* Fetch RD */ + if (pnt + 8 > lim) + { + zlog_err ("not enough bytes for RD left in NLRI?"); + return -1; + } + + /* Copy routing distinguisher to rd. */ + memcpy (&prd.val, pnt, 8); + pnt += 8; + + /* Fetch ESI */ + if (pnt + 10 > lim) + { + zlog_err ("not enough bytes for ESI left in NLRI?"); + return -1; + } + memcpy(&evpn.eth_s_id.val, pnt, 10); + pnt += 10; + + /* Fetch Ethernet Tag */ + if (pnt + 4 > lim) + { + zlog_err ("not enough bytes for Eth Tag left in NLRI?"); + return -1; + } + + if (route_type == EVPN_IP_PREFIX) + { + p_evpn_p->route_type = route_type; + memcpy (&(p_evpn_p->eth_tag), pnt, 4); + p_evpn_p->eth_tag = ntohl(p_evpn_p->eth_tag); + pnt += 4; + + /* Fetch IP prefix length. */ + p_evpn_p->ip_prefix_length = *pnt++; + + if (p_evpn_p->ip_prefix_length > 128) + { + zlog_err ("invalid prefixlen %d in EVPN NLRI?", p.prefixlen); + return -1; + } + /* determine IPv4 or IPv6 prefix */ + if(route_length - 4 - 10 - 8 - 3 /* label to be read */ >= 32) + { + p_evpn_p->flags = IP_PREFIX_V6; + memcpy (&(p_evpn_p->ip.v4_addr), pnt, 16); + pnt += 16; + memcpy(&evpn.gw_ip.ipv6, pnt, 16); + pnt += 16; + } + else + { + p_evpn_p->flags = IP_PREFIX_V4; + memcpy (&(p_evpn_p->ip.v4_addr), pnt, 4); + pnt += 4; + memcpy(&evpn.gw_ip.ipv4, pnt, 4); + pnt += 4; + } + p.family = AFI_L2VPN; + if (p_evpn_p->flags == IP_PREFIX_V4) + p.prefixlen = (u_char)PREFIX_LEN_ROUTE_TYPE_5_IPV4; + else + p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6; + p.family = AF_ETHERNET; + } + + /* Fetch Label */ + if (pnt + 3 > lim) + { + zlog_err ("not enough bytes for Label left in NLRI?"); + return -1; + } + pnt_label = pnt; + + pnt += 3; + + if (!withdraw) + { + bgp_update (peer, &p, addpath_id, attr, AFI_L2VPN, SAFI_EVPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, + pnt_label, 0, &evpn); + } + else + { + bgp_withdraw (peer, &p, addpath_id, attr, AFI_L2VPN, SAFI_EVPN, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + &prd, pnt_label, &evpn); + } + } + + /* Packet length consistency check. */ + if (pnt != lim) + return -1; + + return 0; +} diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h new file mode 100644 index 0000000000..a493962350 --- /dev/null +++ b/bgpd/bgp_evpn.h @@ -0,0 +1,36 @@ +/* E-VPN header for packet handling + Copyright (C) 2016 6WIND + +This file is part of Free Range Routing. + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _QUAGGA_BGP_EVPN_H +#define _QUAGGA_BGP_EVPN_H + +extern int bgp_nlri_parse_evpn (struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw); + +/* EVPN route types as per RFC7432 and + * as per draft-ietf-bess-evpn-prefix-advertisement-02 + */ +#define EVPN_ETHERNET_AUTO_DISCOVERY 1 +#define EVPN_MACIP_ADVERTISEMENT 2 +#define EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG 3 +#define EVPN_ETHERNET_SEGMENT 4 +#define EVPN_IP_PREFIX 5 + +#endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index cfdb9f3ce6..3e11e522fa 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -288,12 +288,12 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, if (attr) { bgp_update (peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0, NULL); } else { bgp_withdraw (peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, NULL); } } /* Packet length consistency check. */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index c7453509fa..9a8722a749 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -49,6 +49,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_evpn.h" #include "bgpd/bgp_encap.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" @@ -1327,19 +1328,24 @@ bgp_update_explicit_eors (struct peer *peer) bgp_check_update_delay(peer->bgp); } -/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers */ +/* Frontend for NLRI parsing, to fan-out to AFI/SAFI specific parsers + * mp_withdraw, if set, is used to nullify attr structure on most of the calling safi function + * and for evpn, passed as parameter + */ int -bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) +bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet, int mp_withdraw) { switch (packet->safi) { case SAFI_UNICAST: case SAFI_MULTICAST: - return bgp_nlri_parse_ip (peer, attr, packet); + return bgp_nlri_parse_ip (peer, mp_withdraw?NULL:attr, packet); case SAFI_MPLS_VPN: - return bgp_nlri_parse_vpn (peer, attr, packet); + return bgp_nlri_parse_vpn (peer, mp_withdraw?NULL:attr, packet); case SAFI_ENCAP: - return bgp_nlri_parse_encap (peer, attr, packet); + return bgp_nlri_parse_encap (peer, mp_withdraw?NULL:attr, packet); + case SAFI_EVPN: + return bgp_nlri_parse_evpn (peer, attr, packet, mp_withdraw); } return -1; } @@ -1531,11 +1537,11 @@ bgp_update_receive (struct peer *peer, bgp_size_t size) { case NLRI_UPDATE: case NLRI_MP_UPDATE: - nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i]); + nlri_ret = bgp_nlri_parse (peer, NLRI_ATTR_ARG, &nlris[i], 0); break; case NLRI_WITHDRAW: case NLRI_MP_WITHDRAW: - nlri_ret = bgp_nlri_parse (peer, NULL, &nlris[i]); + nlri_ret = bgp_nlri_parse (peer, &attr, &nlris[i], 1); break; default: nlri_ret = -1; diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 78855c3425..ea5c7a8998 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -55,7 +55,7 @@ extern void bgp_default_withdraw_send (struct peer *, afi_t, safi_t); extern int bgp_capability_receive (struct peer *, bgp_size_t); -extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); +extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *, int mp_withdraw); extern void bgp_update_restarted_peers (struct peer *); extern void bgp_update_implicit_eors (struct peer *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 84c0ee1021..2391964dad 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2341,7 +2341,7 @@ int bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, u_char *tag, - int soft_reconfig) + int soft_reconfig, struct bgp_route_evpn* evpn) { int ret; int aspath_loop_count = 0; @@ -2851,7 +2851,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, int bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, - struct prefix_rd *prd, u_char *tag) + struct prefix_rd *prd, u_char *tag, struct bgp_route_evpn *evpn) { struct bgp *bgp; char buf[SU_ADDRSTRLEN]; @@ -3049,7 +3049,7 @@ bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, ret = bgp_update (peer, &rn->p, ain->addpath_rx_id, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - prd, tag, 1); + prd, tag, 1, NULL); if (ret < 0) { @@ -3615,10 +3615,10 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr, /* Normal process. */ if (attr) ret = bgp_update (peer, &p, addpath_id, attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL); else ret = bgp_withdraw (peer, &p, addpath_id, attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, NULL); /* Address family configuration mismatch or maximum-prefix count overflow. */ diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 2103338b7d..4a24b0f376 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgp_table.h" struct bgp_nexthop_cache; +struct bgp_route_evpn; enum bgp_show_type { @@ -319,10 +320,11 @@ extern int bgp_static_unset_safi (safi_t safi, struct vty *, const char *, /* this is primarily for MPLS-VPN */ extern int bgp_update (struct peer *, struct prefix *, u_int32_t, struct attr *, - afi_t, safi_t, int, int, struct prefix_rd *, - u_char *, int); + afi_t, safi_t, int, int, struct prefix_rd *, + u_char *, int, struct bgp_route_evpn *); extern int bgp_withdraw (struct peer *, struct prefix *, u_int32_t, struct attr *, - afi_t, safi_t, int, int, struct prefix_rd *, u_char *); + afi_t, safi_t, int, int, struct prefix_rd *, u_char *, + struct bgp_route_evpn *); /* for bgp_nexthop and bgp_damp */ extern void bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 1cad7c5a15..5e43400237 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -66,6 +66,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/rfapi/bgp_rfapi_cfg.h" #include "bgpd/rfapi/rfapi_backend.h" #endif +#include "bgpd/bgp_evpn.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_vty.h" diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index f20e9ed674..9b2dc25823 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -340,7 +340,7 @@ vnc_direct_bgp_add_route_ce ( iattr, /* bgp_update copies this attr */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ NULL, /* tag not used for unicast */ - 0); + 0, NULL); /* EVPN not used */ bgp_attr_unintern (&iattr); } @@ -425,7 +425,7 @@ vnc_direct_bgp_del_route_ce ( 0, /* addpath_id */ NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL); /* tag not used for unicast */ + NULL, NULL); /* tag not used for unicast */ } @@ -534,7 +534,7 @@ vnc_direct_bgp_vpn_disable_ce (struct bgp *bgp, afi_t afi) 0, /* addpath_id */ NULL, /* ignored */ AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL); /* tag not used for unicast */ + NULL, NULL); /* tag not used for unicast */ } } } @@ -911,7 +911,7 @@ vnc_direct_bgp_add_prefix ( iattr, /* bgp_update copies it */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ NULL, /* tag not used for unicast */ - 0); + 0, NULL); /* EVPN not used */ bgp_attr_unintern (&iattr); } @@ -1011,7 +1011,7 @@ vnc_direct_bgp_del_prefix ( 0, /* addpath_id */ NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL); /* tag not used for unicast */ + NULL, NULL); /* tag not used for unicast */ } } } @@ -1150,7 +1150,7 @@ vnc_direct_bgp_add_nve (struct bgp *bgp, struct rfapi_descriptor *rfd) iattr, /* bgp_update copies it */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ NULL, /* tag not used for unicast */ - 0); + 0, NULL); /* EVPN not used */ bgp_attr_unintern (&iattr); @@ -1250,7 +1250,7 @@ vnc_direct_bgp_del_nve (struct bgp *bgp, struct rfapi_descriptor *rfd) 0, /* addpath_id */ NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL); /* tag not used for unicast */ + NULL, NULL); /* tag not used for unicast */ } } @@ -1377,7 +1377,7 @@ vnc_direct_bgp_add_group_afi ( iattr, /* bgp_update copies it */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ NULL, /* tag not used for unicast */ - 0); + 0, NULL); /* EVPN not used */ bgp_attr_unintern (&iattr); } @@ -1462,7 +1462,7 @@ vnc_direct_bgp_del_group_afi ( 0, /* addpath_id */ NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL); /* tag not used for unicast */ + NULL, NULL); /* tag not used for unicast */ } } @@ -1540,7 +1540,7 @@ vnc_direct_bgp_unexport_table ( 0, /* addpath_id */ NULL, /* attr, ignored */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL); /* tag not used for unicast */ + NULL, NULL); /* tag not used for unicast, EVPN neither */ } } @@ -1777,8 +1777,8 @@ vnc_direct_bgp_rh_add_route ( 0, /* addpath_id */ iattr, /* bgp_update copies this attr */ afi, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, /* tag not used for unicast */ - 0); + NULL, /* tag not used for unicast, EVPN neither */ + 0, NULL); /* EVPN not used */ bgp_attr_unintern (&iattr); } @@ -1801,7 +1801,7 @@ vncExportWithdrawTimer (struct thread *t) eti->type, eti->subtype, NULL, /* RD not used for unicast */ - NULL); /* tag not used for unicast */ + NULL, NULL); /* tag not used for unicast, EVPN neither */ /* * Free the eti @@ -2019,8 +2019,8 @@ vnc_direct_bgp_rh_vpn_enable (struct bgp *bgp, afi_t afi) 0, /* addpath_id */ iattr, /* bgp_update copies it */ AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL, /* tag not used for unicast */ - 0); + NULL, /* tag not used for unicast, EVPN neither */ + 0, NULL); /* EVPN not used */ bgp_attr_unintern (&iattr); } } @@ -2085,7 +2085,7 @@ vnc_direct_bgp_rh_vpn_disable (struct bgp *bgp, afi_t afi) 0, /* addpath_id */ NULL, /* ignored */ AFI_IP, SAFI_UNICAST, ZEBRA_ROUTE_VNC_DIRECT_RH, BGP_ROUTE_REDISTRIBUTE, NULL, /* RD not used for unicast */ - NULL); /* tag not used for unicast */ + NULL, NULL); /* tag not used for unicast, EVPN neither */ } } } From b2055847534536fcb6503a433e71b68df14b1d22 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 23 Jan 2017 14:42:02 +0100 Subject: [PATCH 13/64] tests: update bgp_nlri_parse function usage in bgp testing Because the bgp_nlri_parse function has been extended with one parameter, when doing bgp testing against some packets, the correct call to bgp_nlri_parse must be done. Signed-off-by: Philippe Guibert --- tests/bgpd/test_mp_attr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index 397612c315..96a0e0759d 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -725,9 +725,9 @@ parse_test (struct peer *peer, struct test_segment *t, int type) if (!parse_ret) { if (type == BGP_ATTR_MP_REACH_NLRI) - nlri_ret = bgp_nlri_parse (peer, &attr, &nlri); + nlri_ret = bgp_nlri_parse (peer, &attr, &nlri, 0); else - nlri_ret = bgp_nlri_parse (peer, NULL, &nlri); + nlri_ret = bgp_nlri_parse (peer, &attr, &nlri, 1); } zlog_err("xxxxxxxxxxxxxxxx nlri ret %u", nlri_ret); handle_result (peer, t, parse_ret, nlri_ret); From fd6c6cb49b37168dc5fd936b046299009da2fc7e Mon Sep 17 00:00:00 2001 From: vivek Date: Tue, 2 Aug 2016 11:51:35 -0700 Subject: [PATCH 14/64] lib: Functions related to AF_ETHERNET Signed-off-by: Vivek Venkatraman --- lib/prefix.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index f4012a5957..06ed00baa9 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -209,7 +209,7 @@ afi2family (afi_t afi) return AF_INET; else if (afi == AFI_IP6) return AF_INET6; - else if (afi == AFI_ETHER) + else if (afi == AFI_L2VPN) return AF_ETHERNET; return 0; } @@ -222,7 +222,7 @@ family2afi (int family) else if (family == AF_INET6) return AFI_IP6; else if (family == AF_ETHERNET) - return AFI_ETHER; + return AFI_L2VPN; return 0; } @@ -304,6 +304,10 @@ prefix_copy (struct prefix *dest, const struct prefix *src) dest->u.prefix4 = src->u.prefix4; else if (src->family == AF_INET6) dest->u.prefix6 = src->u.prefix6; + else if (src->family == AF_ETHERNET) + { + memcpy (&dest->u.prefix_evpn, &src->u.prefix_evpn, sizeof (struct evpn_addr)); + } else if (src->family == AF_UNSPEC) { dest->u.lp.id = src->u.lp.id; @@ -346,10 +350,9 @@ prefix_same (const struct prefix *p1, const struct prefix *p2) if (p1->family == AF_INET6 ) if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr)) return 1; - if (p1->family == AF_ETHERNET) { - if (!memcmp(p1->u.prefix_eth.octet, p2->u.prefix_eth.octet, ETHER_ADDR_LEN)) - return 1; - } + if (p1->family == AF_ETHERNET ) + if (!memcmp (&p1->u.prefix_evpn, &p2->u.prefix_evpn, sizeof (struct evpn_addr))) + return 1; } return 0; } @@ -412,6 +415,9 @@ prefix_common_bits (const struct prefix *p1, const struct prefix *p2) length = IPV4_MAX_BYTELEN; if (p1->family == AF_INET6) length = IPV6_MAX_BYTELEN; + if (p1->family == AF_ETHERNET) + length = 8 * sizeof (struct evpn_addr); + if (p1->family != p2->family || !length) return -1; From 78b81eaa44d74c988a681b96574a7b6897e7dea0 Mon Sep 17 00:00:00 2001 From: vivek Date: Tue, 9 Aug 2016 15:55:51 -0700 Subject: [PATCH 15/64] lib: Enhance prefix dump for EVPN prefixes This commit is also taking into account changes related to srcdes feature introduction in zebra folder. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Signed-off-by: Philippe Guibert Ticket: CM-12262 Reviewed By: CCR-5065 Testing Done: Manual Signed-off-by: Philippe Guibert --- lib/prefix.c | 42 +++++++++++++++++++++++++++++------------- lib/prefix.h | 9 ++++++--- lib/srcdest_table.c | 4 ++-- lib/srcdest_table.h | 4 ++-- zebra/rib.h | 4 ++-- zebra/zebra_rib.c | 4 ++-- 6 files changed, 43 insertions(+), 24 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index 06ed00baa9..6d3de3d6c6 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -859,23 +859,39 @@ str2prefix (const char *str, struct prefix *p) } const char * -prefix2str (union prefix46constptr pu, char *str, int size) +prefix2str (union prefixconstptr pu, char *str, int size) { const struct prefix *p = pu.p; + char buf[PREFIX2STR_BUFFER]; - if (p->family == AF_ETHERNET) + switch (p->family) { - snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d", - p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1], - p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3], - p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5], - p->prefixlen); - } - else - { - char buf[PREFIX2STR_BUFFER]; - inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)); - snprintf(str, size, "%s/%d", buf, p->prefixlen); + u_char family; + + case AF_INET: + case AF_INET6: + snprintf (str, size, "%s/%d", + inet_ntop (p->family, &p->u.prefix, buf, PREFIX2STR_BUFFER), + p->prefixlen); + break; + + case AF_ETHERNET: + if (p->u.prefix_evpn.route_type == 5) + { + family = (p->u.prefix_evpn.flags & (IP_ADDR_V4 | IP_PREFIX_V4)) ? + AF_INET : AF_INET6; + snprintf (str, size, "[%d]:[%u][%s]/%d", + p->u.prefix_evpn.route_type, + p->u.prefix_evpn.eth_tag, + inet_ntop (family, &p->u.prefix_evpn.ip.addr, + buf, PREFIX2STR_BUFFER), + p->prefixlen); + } + break; + + default: + sprintf (str, "UNK prefix"); + break; } return str; diff --git a/lib/prefix.h b/lib/prefix.h index 1756dd21c8..5c1c71a7c0 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -69,6 +69,7 @@ struct evpn_addr u_char ip_prefix_length; union { + u_char addr; struct in_addr v4_addr; struct in6_addr v6_addr; } ip; @@ -185,18 +186,20 @@ struct prefix_sg * side, which strips type safety since the cast will accept any pointer * type.) */ -union prefix46ptr +union prefixptr { struct prefix *p; struct prefix_ipv4 *p4; struct prefix_ipv6 *p6; + struct prefix_evpn *evp; } __attribute__ ((transparent_union)); -union prefix46constptr +union prefixconstptr { const struct prefix *p; const struct prefix_ipv4 *p4; const struct prefix_ipv6 *p6; + const struct prefix_evpn *evp; } __attribute__ ((transparent_union)); #ifndef INET_ADDRSTRLEN @@ -270,7 +273,7 @@ extern int str2prefix (const char *, struct prefix *); #define PREFIX2STR_BUFFER PREFIX_STRLEN -extern const char *prefix2str (union prefix46constptr, char *, int); +extern const char *prefix2str (union prefixconstptr, char *, int); extern int prefix_match (const struct prefix *, const struct prefix *); extern int prefix_same (const struct prefix *, const struct prefix *); extern int prefix_cmp (const struct prefix *, const struct prefix *); diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c index dd148fa41d..04c9eff79a 100644 --- a/lib/srcdest_table.c +++ b/lib/srcdest_table.c @@ -242,7 +242,7 @@ srcdest_route_next(struct route_node *rn) } struct route_node * -srcdest_rnode_get (struct route_table *table, union prefix46ptr dst_pu, +srcdest_rnode_get (struct route_table *table, union prefixptr dst_pu, struct prefix_ipv6 *src_p) { struct prefix_ipv6 *dst_p = dst_pu.p6; @@ -253,7 +253,7 @@ srcdest_rnode_get (struct route_table *table, union prefix46ptr dst_pu, } struct route_node * -srcdest_rnode_lookup (struct route_table *table, union prefix46ptr dst_pu, +srcdest_rnode_lookup (struct route_table *table, union prefixptr dst_pu, struct prefix_ipv6 *src_p) { struct prefix_ipv6 *dst_p = dst_pu.p6; diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h index 59111b5d17..207f5d121d 100644 --- a/lib/srcdest_table.h +++ b/lib/srcdest_table.h @@ -57,10 +57,10 @@ extern route_table_delegate_t _srcdest_srcnode_delegate; extern struct route_table *srcdest_table_init(void); extern struct route_node *srcdest_rnode_get(struct route_table *table, - union prefix46ptr dst_pu, + union prefixptr dst_pu, struct prefix_ipv6 *src_p); extern struct route_node *srcdest_rnode_lookup(struct route_table *table, - union prefix46ptr dst_pu, + union prefixptr dst_pu, struct prefix_ipv6 *src_p); extern void srcdest_rnode_prefixes (struct route_node *rn, struct prefix **p, struct prefix **src_p); diff --git a/zebra/rib.h b/zebra/rib.h index b246b89a53..c0cde50baf 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -314,8 +314,8 @@ extern void rib_lookup_and_dump (struct prefix_ipv4 *, vrf_id_t); extern void rib_lookup_and_pushup (struct prefix_ipv4 *, vrf_id_t); #define rib_dump(prefix, src, rib) _rib_dump(__func__, prefix, src, rib) extern void _rib_dump (const char *, - union prefix46constptr, - union prefix46constptr, const struct rib *); + union prefixconstptr, + union prefixconstptr, const struct rib *); extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *, vrf_id_t); #define ZEBRA_RIB_LOOKUP_ERROR -1 diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 13418c509e..08874f22fc 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2135,8 +2135,8 @@ rib_delnode (struct route_node *rn, struct rib *rib) */ void _rib_dump (const char * func, - union prefix46constptr pp, - union prefix46constptr src_pp, + union prefixconstptr pp, + union prefixconstptr src_pp, const struct rib * rib) { const struct prefix *p = pp.p; From 906ad49b5e3bda51cf5ad07ea22b46a6597ec292 Mon Sep 17 00:00:00 2001 From: vivek Date: Tue, 9 Aug 2016 16:02:03 -0700 Subject: [PATCH 16/64] bgpd: Update logging for EVPN prefixes Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Signed-off-by: Philippe Guibert Ticket: CM-12262 Reviewed By: CCR-5065 Testing Done: Manual --- bgpd/bgp_debug.c | 29 ++++++++++ bgpd/bgp_debug.h | 5 ++ bgpd/bgp_route.c | 114 ++++++++++++++------------------------- bgpd/bgp_updgrp_packet.c | 46 ++++++++-------- 4 files changed, 98 insertions(+), 96 deletions(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index ab05878210..1292de626d 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -38,6 +38,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_debug.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_updgrp.h" +#include "bgpd/bgp_mplsvpn.h" unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_neighbor_events; @@ -2086,3 +2087,31 @@ bgp_debug_zebra (struct prefix *p) return 0; } + +const char * +bgp_debug_rdpfxpath2str (struct prefix_rd *prd, union prefixconstptr pu, + int addpath_valid, u_int32_t addpath_id, + char *str, int size) +{ + char rd_buf[RD_ADDRSTRLEN]; + char pfx_buf[PREFIX_STRLEN]; + char pathid_buf[20]; + + if (size < BGP_PRD_PATH_STRLEN) + return NULL; + + /* Note: Path-id is created by default, but only included in update sometimes. */ + pathid_buf[0] = '\0'; + if (addpath_valid) + sprintf(pathid_buf, " with addpath ID %d", addpath_id); + + if (prd) + snprintf (str, size, "RD %s %s%s", + prefix_rd2str(prd, rd_buf, sizeof (rd_buf)), + prefix2str (pu, pfx_buf, sizeof (pfx_buf)), pathid_buf); + else + snprintf (str, size, "%s%s", + prefix2str (pu, pfx_buf, sizeof (pfx_buf)), pathid_buf); + + return str; +} diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 00fb670a47..23ea7b0e52 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -36,6 +36,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* dump detail */ #define DUMP_DETAIL 32 +/* RD + Prefix + Path-Id */ +#define BGP_PRD_PATH_STRLEN (PREFIX_STRLEN + RD_ADDRSTRLEN + 20) + extern int dump_open; extern int dump_update; extern int dump_keepalive; @@ -151,4 +154,6 @@ extern int bgp_debug_bestpath(struct prefix *p); extern int bgp_debug_zebra(struct prefix *p); extern int bgp_debug_count(void); +extern const char *bgp_debug_rdpfxpath2str (struct prefix_rd *, union prefixconstptr, + int, u_int32_t, char *, int); #endif /* _QUAGGA_BGP_DEBUG_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 2391964dad..df2c3d8e73 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1192,7 +1192,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp, struct bgp *bgp; struct attr *riattr; struct peer_af *paf; - char buf[SU_ADDRSTRLEN]; + char buf[PREFIX_STRLEN]; int ret; int transparent; int reflect; @@ -1224,8 +1224,7 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp, * direct and direct_ext type routes originate internally even * though they can have peer pointers that reference other systems */ - char buf[BUFSIZ]; - prefix2str(p, buf, BUFSIZ); + prefix2str(p, buf, PREFIX_STRLEN); zlog_debug("%s: pfx %s bgp_direct->vpn route peer safe", __func__, buf); samepeer_safe = 1; } @@ -1295,11 +1294,9 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp, (IPV4_ADDR_SAME (&onlypeer->remote_id, &riattr->extra->originator_id))) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) - zlog_debug ("%s [Update:SEND] %s/%d originator-id is same as " + zlog_debug ("%s [Update:SEND] %s originator-id is same as " "remote router-id", - onlypeer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen); + onlypeer->host, prefix2str (p, buf, sizeof (buf))); return 0; } @@ -1313,10 +1310,8 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp, if (prefix_list_apply (peer->orf_plist[afi][safi], p) == PREFIX_DENY) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) - zlog_debug ("%s [Update:SEND] %s/%d is filtered via ORF", - peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen); + zlog_debug ("%s [Update:SEND] %s is filtered via ORF", + peer->host, prefix2str (p, buf, sizeof (buf))); return 0; } } @@ -1325,10 +1320,8 @@ subgroup_announce_check (struct bgp_info *ri, struct update_subgroup *subgrp, if (bgp_output_filter (peer, p, riattr, afi, safi) == FILTER_DENY) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) - zlog_debug ("%s [Update:SEND] %s/%d is filtered", - peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen); + zlog_debug ("%s [Update:SEND] %s is filtered", + peer->host, prefix2str (p, buf, sizeof (buf))); return 0; } @@ -2277,14 +2270,6 @@ info_make (int type, int sub_type, u_short instance, struct peer *peer, struct a return new; } -static void -bgp_info_addpath_rx_str(u_int32_t addpath_id, char *buf) -{ - if (addpath_id) - sprintf(buf, " with addpath ID %d", addpath_id); -} - - /* Check if received nexthop is valid or not. */ static int bgp_update_martian_nexthop (struct bgp *bgp, afi_t afi, safi_t safi, struct attr *attr) @@ -2353,8 +2338,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct bgp_info *ri; struct bgp_info *new; const char *reason; - char buf[SU_ADDRSTRLEN]; - char buf2[30]; + char pfx_buf[BGP_PRD_PATH_STRLEN]; int connected = 0; int do_loop_check = 1; #if ENABLE_BGP_VNC @@ -2471,13 +2455,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) { if (bgp_debug_update(peer, p, NULL, 1)) - { - bgp_info_addpath_rx_str(addpath_id, buf2); - zlog_debug ("%s rcvd %s/%d%s", - peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, buf2); - } + zlog_debug ("%s rcvd %s", peer->host, + bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, + addpath_id, pfx_buf, sizeof (pfx_buf))); if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED) { @@ -2495,11 +2475,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - bgp_info_addpath_rx_str(addpath_id, buf2); - zlog_debug ("%s rcvd %s/%d%s...duplicate ignored", + zlog_debug ("%s rcvd %s...duplicate ignored", peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, buf2); + bgp_debug_rdpfxpath2str (prd, p, addpath_id ? + 1 : 0, addpath_id, pfx_buf, sizeof (pfx_buf))); } /* graceful restart STALE flag unset. */ @@ -2520,25 +2499,18 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { if (bgp_debug_update(peer, p, NULL, 1)) - { - bgp_info_addpath_rx_str(addpath_id, buf2); - zlog_debug ("%s rcvd %s/%d%s, flapped quicker than processing", - peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, buf2); - } + zlog_debug ("%s rcvd %s, flapped quicker than processing", + peer->host, + bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, + addpath_id, pfx_buf, sizeof (pfx_buf))); bgp_info_restore (rn, ri); } /* Received Logging. */ if (bgp_debug_update(peer, p, NULL, 1)) - { - bgp_info_addpath_rx_str(addpath_id, buf2); - zlog_debug ("%s rcvd %s/%d%s", - peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, buf2); - } + zlog_debug ("%s rcvd %s", peer->host, + bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, + addpath_id, pfx_buf, sizeof (pfx_buf))); /* graceful restart STALE flag unset. */ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) @@ -2712,11 +2684,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - bgp_info_addpath_rx_str(addpath_id, buf2); - zlog_debug ("%s rcvd %s/%d%s", - peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, buf2); + zlog_debug ("%s rcvd %s", peer->host, + bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, + addpath_id, pfx_buf, sizeof (pfx_buf))); } /* Make new BGP info. */ @@ -2822,11 +2792,10 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, peer->rcvd_attr_printed = 1; } - bgp_info_addpath_rx_str(addpath_id, buf2); - zlog_debug ("%s rcvd UPDATE about %s/%d%s -- DENIED due to: %s", + zlog_debug ("%s rcvd UPDATE about %s -- DENIED due to: %s", peer->host, - inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, buf2, reason); + bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, + addpath_id, pfx_buf, sizeof (pfx_buf)), reason); } if (ri) @@ -2854,8 +2823,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id, struct prefix_rd *prd, u_char *tag, struct bgp_route_evpn *evpn) { struct bgp *bgp; - char buf[SU_ADDRSTRLEN]; - char buf2[30]; + char pfx_buf[BGP_PRD_PATH_STRLEN]; struct bgp_node *rn; struct bgp_info *ri; @@ -2885,10 +2853,10 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id, if (!bgp_adj_in_unset (rn, peer, addpath_id)) { if (bgp_debug_update (peer, p, NULL, 1)) - zlog_debug ("%s withdrawing route %s/%d " - "not in adj-in", peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen); + zlog_debug ("%s withdrawing route %s not in adj-in", + peer->host, + bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, + addpath_id, pfx_buf, sizeof (pfx_buf))); bgp_unlock_node (rn); return 0; } @@ -2902,20 +2870,20 @@ bgp_withdraw (struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Logging. */ if (bgp_debug_update(peer, p, NULL, 1)) { - bgp_info_addpath_rx_str(addpath_id, buf2); - zlog_debug ("%s rcvd UPDATE about %s/%d%s -- withdrawn", - peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, buf2); + zlog_debug ("%s rcvd UPDATE about %s -- withdrawn", + peer->host, + bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, + addpath_id, pfx_buf, sizeof (pfx_buf))); } /* Withdraw specified route from routing table. */ if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) bgp_rib_withdraw (rn, ri, peer, afi, safi, prd); else if (bgp_debug_update(peer, p, NULL, 1)) - zlog_debug ("%s Can't find the route %s/%d", peer->host, - inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen); + zlog_debug ("%s Can't find the route %s", + peer->host, + bgp_debug_rdpfxpath2str (prd, p, addpath_id ? 1 : 0, + addpath_id, pfx_buf, sizeof (pfx_buf))); /* Unlock bgp_node_get() lock. */ bgp_unlock_node (rn); diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 79c11358fe..ca1bd1e0e6 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -53,6 +53,7 @@ #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" +#include "bgpd/bgp_mplsvpn.h" /******************** * PRIVATE FUNCTIONS @@ -617,6 +618,7 @@ static void bgp_info_addpath_tx_str (int addpath_encode, u_int32_t addpath_tx_id, char *buf) { + buf[0] = '\0'; if (addpath_encode) sprintf(buf, " with addpath ID %d", addpath_tx_id); } @@ -648,6 +650,7 @@ subgroup_update_packet (struct update_subgroup *subgrp) int num_pfx = 0; int addpath_encode = 0; u_int32_t addpath_tx_id = 0; + struct prefix_rd *prd = NULL; if (!subgrp) return NULL; @@ -751,7 +754,6 @@ subgroup_update_packet (struct update_subgroup *subgrp) else { /* Encode the prefix in MP_REACH_NLRI attribute */ - struct prefix_rd *prd = NULL; u_char *tag = NULL; if (rn->prn) @@ -772,8 +774,7 @@ subgroup_update_packet (struct update_subgroup *subgrp) if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0)) { - char buf[INET6_BUFSIZ]; - char tx_id_buf[30]; + char pfx_buf[BGP_PRD_PATH_STRLEN]; if (!send_attr_printed) { @@ -782,11 +783,11 @@ subgroup_update_packet (struct update_subgroup *subgrp) send_attr_printed = 1; } - bgp_info_addpath_tx_str (addpath_encode, addpath_tx_id, tx_id_buf); - zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s", + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s", subgrp->update_group->id, subgrp->id, - inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), - rn->p.prefixlen, tx_id_buf); + bgp_debug_rdpfxpath2str (prd, &rn->p, addpath_encode, + addpath_tx_id, + pfx_buf, sizeof (pfx_buf))); } /* Synchnorize attribute. */ @@ -863,6 +864,8 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) int num_pfx = 0; int addpath_encode = 0; u_int32_t addpath_tx_id = 0; + struct prefix_rd *prd = NULL; + if (!subgrp) return NULL; @@ -905,8 +908,6 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) stream_put_prefix_addpath (s, &rn->p, addpath_encode, addpath_tx_id); else { - struct prefix_rd *prd = NULL; - if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; @@ -928,13 +929,13 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) if (bgp_debug_update(NULL, &rn->p, subgrp->update_group, 0)) { - char buf[INET6_BUFSIZ]; - char tx_id_buf[30]; - bgp_info_addpath_tx_str (addpath_encode, addpath_tx_id, tx_id_buf); - zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s -- unreachable", + char pfx_buf[BGP_PRD_PATH_STRLEN]; + + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s -- unreachable", subgrp->update_group->id, subgrp->id, - inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), - rn->p.prefixlen, tx_id_buf); + bgp_debug_rdpfxpath2str (prd, &rn->p, + addpath_encode, addpath_tx_id, + pfx_buf, sizeof (pfx_buf))); } subgrp->scount--; @@ -1010,16 +1011,16 @@ subgroup_default_update_packet (struct update_subgroup *subgrp, if (bgp_debug_update(NULL, &p, subgrp->update_group, 0)) { char attrstr[BUFSIZ]; - char buf[INET6_BUFSIZ]; + char buf[PREFIX_STRLEN]; char tx_id_buf[30]; attrstr[0] = '\0'; bgp_dump_attr (peer, attr, attrstr, BUFSIZ); bgp_info_addpath_tx_str (addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, tx_id_buf); - zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s %s", + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s%s %s", (SUBGRP_UPDGRP (subgrp))->id, subgrp->id, - inet_ntop (p.family, &(p.u.prefix), buf, INET6_BUFSIZ), - p.prefixlen, tx_id_buf, attrstr); + prefix2str (&p, buf, sizeof (buf)), + tx_id_buf, attrstr); } s = stream_new (BGP_MAX_PACKET_SIZE); @@ -1084,14 +1085,13 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp) if (bgp_debug_update(NULL, &p, subgrp->update_group, 0)) { - char buf[INET6_BUFSIZ]; + char buf[PREFIX_STRLEN]; char tx_id_buf[INET6_BUFSIZ]; bgp_info_addpath_tx_str (addpath_encode, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, tx_id_buf); - zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s/%d%s -- unreachable", + zlog_debug ("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s%s -- unreachable", (SUBGRP_UPDGRP (subgrp))->id, subgrp->id, - inet_ntop (p.family, &(p.u.prefix), buf, INET6_BUFSIZ), - p.prefixlen, tx_id_buf); + prefix2str (&p, buf, sizeof (buf)), tx_id_buf); } s = stream_new (BGP_MAX_PACKET_SIZE); From 684a7227bd8811b3e222e7d533924e5bc21727e6 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 5 Sep 2016 14:07:01 +0200 Subject: [PATCH 17/64] bgpd: route type 5 internal structures plus processing The commit introduces the changes to be done to carry route type 5 EVPN information in bgp extra attribute information. The commit also handles the update processing for route type 5 information, including ESI, gatewayIP and label information. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr.c | 15 +++++++- bgpd/bgp_attr.h | 11 ++++++ bgpd/bgp_route.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++-- bgpd/bgp_route.h | 4 +++ 4 files changed, 116 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 7dc42e719f..a0e8d5499b 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -419,6 +419,18 @@ encap_finish (void) #endif } +static bool +overlay_index_same(const struct attr_extra *ae1, const struct attr_extra *ae2) +{ + if(!ae1 && ae2) + return false; + if(!ae2 && ae1) + return false; + if(!ae1 && !ae2) + return false; + return !memcmp(&(ae1->evpn_overlay), &(ae2->evpn_overlay), sizeof(struct overlay_index)); +} + /* Unknown transit attribute. */ static struct hash *transit_hash; @@ -730,7 +742,8 @@ attrhash_cmp (const void *p1, const void *p2) #if ENABLE_BGP_VNC && encap_same(ae1->vnc_subtlvs, ae2->vnc_subtlvs) #endif - && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id)) + && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id) + && overlay_index_same(ae1, ae2)) return 1; else if (ae1 || ae2) return 0; diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index c5799ccd0d..3ccf65029c 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _QUAGGA_BGP_ATTR_H #define _QUAGGA_BGP_ATTR_H +#include "bgp_attr_evpn.h" + /* Simple bit mapping. */ #define BITMAP_NBBY 8 @@ -80,6 +82,13 @@ struct bgp_tea_options { #endif +/* Overlay Index Info */ +struct overlay_index +{ + struct eth_segment_id eth_s_id; + union gw_addr gw_ip; +}; + /* Additional/uncommon BGP attributes. * lazily allocated as and when a struct attr * requires it. @@ -131,6 +140,8 @@ struct attr_extra #if ENABLE_BGP_VNC struct bgp_attr_encap_subtlv *vnc_subtlvs; /* VNC-specific */ #endif + /* EVPN */ + struct overlay_index evpn_overlay; }; /* BGP core attribute structure. */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index df2c3d8e73..f80c24dcba 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -68,6 +68,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/rfapi/vnc_import_bgp.h" #include "bgpd/rfapi/vnc_export_bgp.h" #endif +#include "bgpd/bgp_evpn.h" /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; @@ -2270,6 +2271,68 @@ info_make (int type, int sub_type, u_short instance, struct peer *peer, struct a return new; } +static void +overlay_index_update(struct attr *attr, struct eth_segment_id *eth_s_id, union gw_addr *gw_ip) +{ + struct attr_extra *extra; + + if(!attr) + return; + extra = bgp_attr_extra_get(attr); + + if(eth_s_id == NULL) + { + memset(&(extra->evpn_overlay.eth_s_id),0, sizeof(struct eth_segment_id)); + } + else + { + memcpy(&(extra->evpn_overlay.eth_s_id), eth_s_id, sizeof(struct eth_segment_id)); + } + if(gw_ip == NULL) + { + memset(&(extra->evpn_overlay.gw_ip), 0, sizeof(union gw_addr)); + } + else + { + memcpy(&(extra->evpn_overlay.gw_ip),gw_ip, sizeof(union gw_addr)); + } +} + +static bool +overlay_index_equal(afi_t afi, struct bgp_info *info, struct eth_segment_id *eth_s_id, union gw_addr *gw_ip) +{ + struct eth_segment_id *info_eth_s_id, *info_eth_s_id_remote; + union gw_addr *info_gw_ip, *info_gw_ip_remote; + char temp[16]; + + if(afi != AFI_L2VPN) + return true; + if (!info->attr || !info->attr->extra) + { + memset(&temp, 0, 16); + info_eth_s_id = (struct eth_segment_id *)&temp; + info_gw_ip = (union gw_addr *)&temp; + if(eth_s_id == NULL && gw_ip == NULL) + return true; + } + else + { + info_eth_s_id = &(info->attr->extra->evpn_overlay.eth_s_id); + info_gw_ip = &(info->attr->extra->evpn_overlay.gw_ip); + } + if(gw_ip == NULL) + info_gw_ip_remote = (union gw_addr *)&temp; + else + info_gw_ip_remote = gw_ip; + if(eth_s_id == NULL) + info_eth_s_id_remote = (struct eth_segment_id *)&temp; + else + info_eth_s_id_remote = eth_s_id; + if(!memcmp(info_gw_ip, info_gw_ip_remote, sizeof(union gw_addr))) + return false; + return !memcmp(info_eth_s_id, info_eth_s_id_remote, sizeof(struct eth_segment_id)); +} + /* Check if received nexthop is valid or not. */ static int bgp_update_martian_nexthop (struct bgp *bgp, afi_t afi, safi_t safi, struct attr *attr) @@ -2448,7 +2511,9 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, /* Same attribute comes in. */ if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) - && attrhash_cmp (ri->attr, attr_new)) + && attrhash_cmp (ri->attr, attr_new) + && (overlay_index_equal(afi, ri, evpn==NULL?NULL:&evpn->eth_s_id, + evpn==NULL?NULL:&evpn->gw_ip))) { if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == BGP_PEER_EBGP @@ -2568,7 +2633,7 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, ri->attr = attr_new; /* Update MPLS tag. */ - if (safi == SAFI_MPLS_VPN) + if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN) memcpy ((bgp_info_extra_get (ri))->tag, tag, 3); #if ENABLE_BGP_VNC @@ -2589,6 +2654,12 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, } } #endif + /* Update Overlay Index */ + if(afi == AFI_L2VPN) + { + overlay_index_update(ri->attr, evpn==NULL?NULL:&evpn->eth_s_id, + evpn==NULL?NULL:&evpn->gw_ip); + } /* Update bgp route dampening information. */ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) @@ -2693,9 +2764,15 @@ bgp_update (struct peer *peer, struct prefix *p, u_int32_t addpath_id, new = info_make(type, sub_type, 0, peer, attr_new, rn); /* Update MPLS tag. */ - if (safi == SAFI_MPLS_VPN) + if (safi == SAFI_MPLS_VPN || safi == SAFI_EVPN) memcpy ((bgp_info_extra_get (new))->tag, tag, 3); + /* Update Overlay Index */ + if(afi == AFI_L2VPN) + { + overlay_index_update(new->attr, evpn==NULL?NULL:&evpn->eth_s_id, + evpn==NULL?NULL:&evpn->gw_ip); + } /* Nexthop reachability check. */ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) { @@ -3616,6 +3693,8 @@ bgp_static_free (struct bgp_static *bgp_static) { if (bgp_static->rmap.name) XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name); + if(bgp_static->eth_s_id) + XFREE(MTYPE_ATTR, bgp_static->eth_s_id); XFREE (MTYPE_BGP_STATIC, bgp_static); } @@ -3922,6 +4001,8 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, attr.med = bgp_static->igpmetric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + if(afi == AFI_L2VPN) + overlay_index_update(&attr, bgp_static->eth_s_id, NULL); /* Apply route-map. */ if (bgp_static->rmap.name) { @@ -3965,7 +4046,10 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, if (ri) { + union gw_addr add; + memset(&add, 0, sizeof(union gw_addr)); if (attrhash_cmp (ri->attr, attr_new) && + overlay_index_equal(afi, ri, bgp_static->eth_s_id, &add) && !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node (rn); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 4a24b0f376..243c5afb00 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -203,6 +203,10 @@ struct bgp_static /* MPLS label. */ u_char tag[3]; + + /* EVPN */ + struct eth_segment_id *eth_s_id; + char *router_mac; }; #define BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen) \ From e9cf8c8ece32891304b2e7419763d4f6d68248bf Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 5 Sep 2016 15:54:49 +0200 Subject: [PATCH 18/64] bgpd: evpn RT-5 bgp update carries nexthop attribute This patch appends nexthop attribute to EVPN message, in addition to appending gateway IP in RT-5 NLRI itself. In reception, if both informations are stored, then the GW IP information will supersede the NLRI nexthop attribute. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a0e8d5499b..cc2e23ec04 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2812,6 +2812,39 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi, break; } break; + case AFI_L2VPN: + switch (safi) + { + case SAFI_EVPN: + if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV4) + { + stream_putc (s, 12); + stream_putl (s, 0); /* RD = 0, per RFC */ + stream_putl (s, 0); + stream_put (s, &attr->extra->mp_nexthop_global_in, 4); + } + else if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) + { + stream_putc (s, 24); + stream_putl (s, 0); /* RD = 0, per RFC */ + stream_putl (s, 0); + stream_put (s, &attr->extra->mp_nexthop_global, IPV6_MAX_BYTELEN); + } + else if (attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) + { + stream_putc (s, 48); + stream_putl (s, 0); /* RD = 0, per RFC */ + stream_putl (s, 0); + stream_put (s, &attr->extra->mp_nexthop_global, IPV6_MAX_BYTELEN); + stream_putl (s, 0); /* RD = 0, per RFC */ + stream_putl (s, 0); + stream_put (s, &attr->extra->mp_nexthop_local, IPV6_MAX_BYTELEN); + } + break; + break; + default: + break; + } default: break; } From b18825ebc779cd85f9acc40293bb448a09af4cd2 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 5 Sep 2016 14:19:40 +0200 Subject: [PATCH 19/64] bgpd: evpn NLRI route type 5 forging This patch introduces the ability to make route type 5 message when EVPN is enabled. Picked up paramters are collected from the bgp extra attribute structure and are the ESI, the ethernet tag information. In addition to this, nexthop attribute is collected too. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr.c | 27 +++++++++------------ bgpd/bgp_attr.h | 5 ++-- bgpd/bgp_evpn.c | 51 ++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_evpn.h | 4 ++++ bgpd/bgp_packet.c | 1 + bgpd/bgp_updgrp_packet.c | 9 +++---- 6 files changed, 75 insertions(+), 22 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index cc2e23ec04..70d8ffbcc7 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -50,6 +50,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # include "bgp_encap_types.h" # include "bgp_vnc_types.h" #endif +#include "bgp_encap_types.h" +#include "bgp_evpn.h" /* Attribute strings for logging. */ static const struct message attr_str [] = @@ -2858,7 +2860,7 @@ void bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, u_char *tag, int addpath_encode, - u_int32_t addpath_tx_id) + u_int32_t addpath_tx_id, struct attr *attr) { if (safi == SAFI_MPLS_VPN) { @@ -2870,6 +2872,10 @@ bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi, stream_put (s, prd->val, 8); stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); } + else if ((safi == SAFI_EVPN)) + { + bgp_packet_mpattr_route_type_5(s, p, prd, tag, attr); + } else stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id); } @@ -3023,7 +3029,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, AFI_MAX), /* get from NH */ vecarr, attr); bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag, - addpath_encode, addpath_tx_id); + addpath_encode, addpath_tx_id, attr); bgp_packet_mpattr_end(s, mpattrlen_pos); } @@ -3431,21 +3437,10 @@ void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, u_char *tag, int addpath_encode, - u_int32_t addpath_tx_id) + u_int32_t addpath_tx_id, struct attr *attr) { - if (safi == SAFI_MPLS_VPN) - { - /* addpath TX ID */ - if (addpath_encode) - stream_putl(s, addpath_tx_id); - - stream_putc (s, p->prefixlen + 88); - stream_put (s, tag, 3); - stream_put (s, prd->val, 8); - stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); - } - else - stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id); + return bgp_packet_mpattr_prefix (s, afi, safi, p, prd, + tag, addpath_encode, addpath_tx_id, attr); } void diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 3ccf65029c..bd9d7daf4d 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -294,7 +294,8 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi, extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, u_char *tag, int addpath_encode, - u_int32_t addpath_tx_id); + u_int32_t addpath_tx_id, + struct attr *); extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, struct prefix *p); extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep); @@ -303,7 +304,7 @@ extern size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi); extern void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, - u_char *tag, int, u_int32_t); + u_char *tag, int, u_int32_t, struct attr *); extern void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt); static inline int diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index fd785b9a64..a9db7d2360 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -187,3 +187,54 @@ bgp_nlri_parse_evpn (struct peer *peer, struct attr *attr, return 0; } + +void +bgp_packet_mpattr_route_type_5 (struct stream *s, + struct prefix *p, struct prefix_rd *prd, + u_char *label, struct attr *attr) +{ + int len; + char temp[16]; + struct evpn_addr *p_evpn_p; + + memset(&temp, 0, 16); + if(p->family != AF_ETHERNET) + return; + p_evpn_p = &(p->u.prefix_evpn); + if (p_evpn_p->flags & IP_PREFIX_V4) + len = 8; /* ipv4 */ + else + len = 32; /* ipv6 */ + stream_putc (s, EVPN_IP_PREFIX); + stream_putc (s, 8 /* RD */ + 10 /* ESI */ + 4 /* EthTag */ + 1 + len + 3 /* label */); + stream_put (s, prd->val, 8); + if(attr && attr->extra) + stream_put (s, &(attr->extra->evpn_overlay.eth_s_id), 10); + else + stream_put (s, &temp, 10); + stream_putl (s, p_evpn_p->eth_tag); + stream_putc (s, p_evpn_p->ip_prefix_length); + if (p_evpn_p->flags & IP_PREFIX_V4) + stream_put_ipv4(s, p_evpn_p->ip.v4_addr.s_addr); + else + stream_put(s, &p_evpn_p->ip.v6_addr, 16); + if(attr && attr->extra) + { + if (p_evpn_p->flags & IP_PREFIX_V4) + stream_put_ipv4(s, attr->extra->evpn_overlay.gw_ip.ipv4.s_addr); + else + stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6), 16); + } + else + { + if (p_evpn_p->flags & IP_PREFIX_V4) + stream_put_ipv4(s, 0); + else + stream_put(s, &temp, 16); + } + if(label) + stream_put (s, label, 3); + else + stream_put3 (s, 0); + return; +} diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index a493962350..d23509304b 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -24,6 +24,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA extern int bgp_nlri_parse_evpn (struct peer *peer, struct attr *attr, struct bgp_nlri *packet, int withdraw); +extern void +bgp_packet_mpattr_route_type_5 (struct stream *s, + struct prefix *p, struct prefix_rd *prd, + u_char *label, struct attr *attr); /* EVPN route types as per RFC7432 and * as per draft-ietf-bess-evpn-prefix-advertisement-02 */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 9a8722a749..0dbf41a4a1 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -51,6 +51,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_evpn.h" #include "bgpd/bgp_encap.h" +#include "bgpd/bgp_evpn.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_updgrp.h" diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index ca1bd1e0e6..02979602bf 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -766,8 +766,9 @@ subgroup_update_packet (struct update_subgroup *subgrp) (peer_cap_enhe(peer) ? AFI_IP6 : AFI_MAX), /* get from NH */ &vecarr, adv->baa->attr); - bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd, tag, - addpath_encode, addpath_tx_id); + + bgp_packet_mpattr_prefix (snlri, afi, safi, &rn->p, prd, + tag, addpath_encode, addpath_tx_id, adv->baa->attr); } num_pfx++; @@ -922,7 +923,7 @@ subgroup_withdraw_packet (struct update_subgroup *subgrp) } bgp_packet_mpunreach_prefix (s, &rn->p, afi, safi, prd, NULL, - addpath_encode, addpath_tx_id); + addpath_encode, addpath_tx_id, NULL); } num_pfx++; @@ -1126,7 +1127,7 @@ subgroup_default_withdraw_packet (struct update_subgroup *subgrp) mplen_pos = bgp_packet_mpunreach_start (s, afi, safi); bgp_packet_mpunreach_prefix (s, &p, afi, safi, NULL, NULL, addpath_encode, - BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE); + BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL); /* Set the mp_unreach attr's length */ bgp_packet_mpunreach_end (s, mplen_pos); From 25098f9b971e668d83bef83dc3c5b5ab8a6c2363 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 17 Jan 2017 22:21:40 +0100 Subject: [PATCH 20/64] lib: add define of compilation for EVPN in prefix.c Because the prefix structure may include or not evpn sub structure, then HAVE_EVPN compilation define is also used in prefix.c, because it references the sub field evpn of prefix structure. Signed-off-by: Philippe Guibert --- lib/prefix.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index 6d3de3d6c6..514e4f8ebe 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -304,19 +304,17 @@ prefix_copy (struct prefix *dest, const struct prefix *src) dest->u.prefix4 = src->u.prefix4; else if (src->family == AF_INET6) dest->u.prefix6 = src->u.prefix6; +#if defined(HAVE_EVPN) else if (src->family == AF_ETHERNET) { memcpy (&dest->u.prefix_evpn, &src->u.prefix_evpn, sizeof (struct evpn_addr)); } +#endif /* (HAVE_EVPN) */ else if (src->family == AF_UNSPEC) { dest->u.lp.id = src->u.lp.id; dest->u.lp.adv_router = src->u.lp.adv_router; } - else if (src->family == AF_ETHERNET) - { - dest->u.prefix_eth = src->u.prefix_eth; - } else { zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d", @@ -350,9 +348,11 @@ prefix_same (const struct prefix *p1, const struct prefix *p2) if (p1->family == AF_INET6 ) if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr)) return 1; +#if defined(HAVE_EVPN) if (p1->family == AF_ETHERNET ) if (!memcmp (&p1->u.prefix_evpn, &p2->u.prefix_evpn, sizeof (struct evpn_addr))) return 1; +#endif /* (HAVE_EVPN) */ } return 0; } @@ -866,8 +866,6 @@ prefix2str (union prefixconstptr pu, char *str, int size) switch (p->family) { - u_char family; - case AF_INET: case AF_INET6: snprintf (str, size, "%s/%d", @@ -875,9 +873,11 @@ prefix2str (union prefixconstptr pu, char *str, int size) p->prefixlen); break; +#if defined(HAVE_EVPN) case AF_ETHERNET: if (p->u.prefix_evpn.route_type == 5) { + u_char family; family = (p->u.prefix_evpn.flags & (IP_ADDR_V4 | IP_PREFIX_V4)) ? AF_INET : AF_INET6; snprintf (str, size, "[%d]:[%u][%s]/%d", @@ -888,7 +888,7 @@ prefix2str (union prefixconstptr pu, char *str, int size) p->prefixlen); } break; - +#endif /* (HAVE_EVPN) */ default: sprintf (str, "UNK prefix"); break; From 61a5196233e74424d9808f4ffc857bce37f9a4c5 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 17 Jan 2017 22:41:06 +0100 Subject: [PATCH 21/64] bgpd: add support for evpn subnode by using afi/safi parameter Added the possibility to enter in evpn address-family in bgp node, by using 'address-family l2vpn evpn' command. Signed-off-by: Philippe Guibert --- bgpd/bgp_vty.c | 6 ++++-- vtysh/vtysh.c | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 881173d382..efcef248a8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5712,9 +5712,11 @@ DEFUN (address_family_encapv6, DEFUN (address_family_evpn, address_family_evpn_cmd, - "address-family evpn", + "address-family ", "Enter Address Family command mode\n" - "Address family\n") + "EVPN Address family\n" + "Layer2 VPN Address family\n" + "Ethernet Virtual Private Network Subsequent Address Family\n") { #if defined(HAVE_EVPN) vty->node = BGP_EVPN_NODE; diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 255f2e873a..c68ff50a5c 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1213,10 +1213,11 @@ DEFUNSH (VTYSH_BGPD, DEFUNSH (VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd, - "address-family evpn", - "Enter Address Family command mode\n" + "address-family ", "Enter Address Family command mode\n" - "Address family\n") + "EVPN Address family\n" + "Layer2 VPN Address family\n" + "Ethernet Virtual Private Network Subsequent Address Family\n") { #if defined(HAVE_EVPN) vty->node = BGP_EVPN_NODE; From 1e27ef50375b2150d33ad9d591227510f5e10971 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 6 Oct 2016 15:46:45 +0200 Subject: [PATCH 22/64] bgpd: enhance reception of bgp ext. community default gateway This fix permits processing of default gateway extended community if present. This option, if router mac option is not present, will replace it. Also, when exporting route entry to VRF RIB, if VRF is layer 2 type, then the ecommunity related to mac address and router mac are stripped. Signed-off-by: Philippe Guibert --- bgpd/bgp_ecommunity.c | 62 +++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_ecommunity.h | 9 +++++++ 2 files changed, 71 insertions(+) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 6689883d94..89b0fb54af 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -791,3 +791,65 @@ ecommunity_match (const struct ecommunity *ecom1, else return 0; } + +/* return first occurence of type */ +extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *ecom, uint8_t type, uint8_t subtype) +{ + u_int8_t *p; + int c; + struct ecommunity_val *ecom_val; + + /* If the value already exists in the structure return 0. */ + c = 0; + for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) + { + if(p == NULL) + { + continue; + } + if(p[0] == type && p[1] == subtype) + return (struct ecommunity_val *)p; + } + return NULL; +} + +/* remove ext. community matching type and subtype + * return 1 on success ( removed ), 0 otherwise (not present) + */ +extern int ecommunity_strip (struct ecommunity *ecom, uint8_t type, uint8_t subtype) +{ + u_int8_t *p; + int c, found = 0; + /* When this is fist value, just add it. */ + if (ecom == NULL || ecom->val == NULL) + { + return 0; + } + + /* If the value already exists in the structure return 0. */ + c = 0; + for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) + { + if (p[0] == type && p[1] == subtype) + { + found = 1; + break; + } + } + if (found == 0) + return 0; + /* Strip The selected value */ + ecom->size--; + /* size is reduced. no memmove to do */ + p = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE); + if (c != 0) + memcpy(p, ecom->val, c * ECOMMUNITY_SIZE); + if( (ecom->size - c) != 0) + memcpy(p + (c) * ECOMMUNITY_SIZE, + ecom->val + (c +1)* ECOMMUNITY_SIZE, + (ecom->size - c) * ECOMMUNITY_SIZE); + /* shift last ecommunities */ + XFREE (MTYPE_ECOMMUNITY, ecom->val); + ecom->val = p; + return 1; +} diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index c5c58e4260..d4713e5aee 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -31,6 +31,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define ECOMMUNITY_ROUTE_TARGET 0x02 #define ECOMMUNITY_SITE_ORIGIN 0x03 +#define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00 +#define ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL 0x01 +#define ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT 0x02 +#define ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC 0x03 +#define ECOMMUNITY_EVPN_SUBTYPE_DEF_GW 0x0d + /* Low-order octet of the Extended Communities type field for OPAQUE types */ #define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP 0x0c @@ -84,8 +90,11 @@ extern struct ecommunity *ecommunity_str2com (const char *, int, int); extern char *ecommunity_ecom2str (struct ecommunity *, int); extern int ecommunity_match (const struct ecommunity *, const struct ecommunity *); extern char *ecommunity_str (struct ecommunity *); +extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *, uint8_t, uint8_t ); /* for vpn */ extern struct ecommunity *ecommunity_new (void); extern int ecommunity_add_val (struct ecommunity *, struct ecommunity_val *); +extern int ecommunity_strip (struct ecommunity *ecom, uint8_t type, uint8_t subtype); +extern struct ecommunity *ecommunity_new (void); #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ From e82202b7a1a0e70a66cf15db4b5013fa2be165f1 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 9 Aug 2016 10:47:03 +0200 Subject: [PATCH 23/64] bgpd: support for router mac extended community As per draft-ietf-bess-evpn-inter-subnet-forwarding-01, chapter 6.1, a new extended community called router's MAC Extended Community is provided. This community is appended to extended community list. Note that a show API has been changed in order to be able to not display (or not) this new type. Signed-off-by: Philippe Guibert --- bgpd/bgp_clist.c | 4 ++-- bgpd/bgp_ecommunity.c | 42 +++++++++++++++++++++++++++++++++----- bgpd/bgp_ecommunity.h | 4 +++- bgpd/rfapi/bgp_rfapi_cfg.c | 18 ++++++++-------- bgpd/rfapi/rfapi.c | 2 +- bgpd/rfapi/rfapi_import.c | 4 ++-- bgpd/rfapi/rfapi_vty.c | 10 ++++----- 7 files changed, 59 insertions(+), 25 deletions(-) diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index b37034bf29..637c95fa7c 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -1166,14 +1166,14 @@ extcommunity_list_set (struct community_list_handler *ch, } if (ecom) - ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY); + ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY, 0); entry = community_entry_new (); entry->direct = direct; entry->style = style; entry->any = (str ? 0 : 1); if (ecom) - entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST); + entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0); else if (regex) entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); else diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 89b0fb54af..2ea62bbb6d 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -175,7 +175,7 @@ char * ecommunity_str (struct ecommunity *ecom) { if (! ecom->str) - ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY); + ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY, 0); return ecom->str; } @@ -213,7 +213,7 @@ ecommunity_intern (struct ecommunity *ecom) find->refcnt++; if (! find->str) - find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY); + find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY, 0); return find; } @@ -601,9 +601,12 @@ ecommunity_str2com (const char *str, int type, int keyword_included) ECOMMUNITY_FORMAT_ROUTE_MAP ECOMMUNITY_FORMAT_COMMUNITY_LIST ECOMMUNITY_FORMAT_DISPLAY + + Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases. + 0 value displays all */ char * -ecommunity_ecom2str (struct ecommunity *ecom, int format) +ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter) { int i; u_int8_t *pnt; @@ -668,6 +671,11 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) break; case ECOMMUNITY_ENCODE_OPAQUE: + if(filter == ECOMMUNITY_ROUTE_TARGET) + { + first = 0; + continue; + } if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) { uint16_t tunneltype; @@ -678,8 +686,32 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format) first = 0; continue; } - /* fall through */ - + len = sprintf (str_buf + str_pnt, "?"); + str_pnt += len; + first = 0; + continue; + case ECOMMUNITY_ENCODE_EVPN: + if(filter == ECOMMUNITY_ROUTE_TARGET) + { + first = 0; + continue; + } + if (*pnt == ECOMMUNITY_SITE_ORIGIN) + { + char macaddr[6]; + pnt++; + memcpy(&macaddr, pnt, 6); + len = sprintf(str_buf + str_pnt, "EVPN:%02x:%02x:%02x:%02x:%02x:%02x", + macaddr[0], macaddr[1], macaddr[2], + macaddr[3], macaddr[4], macaddr[5]); + str_pnt += len; + first = 0; + continue; + } + len = sprintf (str_buf + str_pnt, "?"); + str_pnt += len; + first = 0; + continue; default: len = sprintf (str_buf + str_pnt, "?"); str_pnt += len; diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index d4713e5aee..356598f6b1 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define ECOMMUNITY_ENCODE_IP 0x01 #define ECOMMUNITY_ENCODE_AS4 0x02 #define ECOMMUNITY_ENCODE_OPAQUE 0x03 +#define ECOMMUNITY_ENCODE_EVPN 0x06 /* Low-order octet of the Extended Communities type field. */ #define ECOMMUNITY_ROUTE_TARGET 0x02 @@ -87,10 +88,11 @@ extern int ecommunity_cmp (const void *, const void *); extern void ecommunity_unintern (struct ecommunity **); extern unsigned int ecommunity_hash_make (void *); extern struct ecommunity *ecommunity_str2com (const char *, int, int); -extern char *ecommunity_ecom2str (struct ecommunity *, int); +extern char *ecommunity_ecom2str (struct ecommunity *, int, int); extern int ecommunity_match (const struct ecommunity *, const struct ecommunity *); extern char *ecommunity_str (struct ecommunity *); extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *, uint8_t, uint8_t ); +extern int ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval); /* for vpn */ extern struct ecommunity *ecommunity_new (void); diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index 50693659b6..2739b1ff10 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -4352,7 +4352,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp) ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list)) { char *b = ecommunity_ecom2str (rfg->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt both %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } @@ -4361,14 +4361,14 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp) if (rfg->rt_import_list) { char *b = ecommunity_ecom2str (rfg->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt import %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } if (rfg->rt_export_list) { char *b = ecommunity_ecom2str (rfg->rt_export_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt export %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } @@ -4483,7 +4483,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp) ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list)) { char *b = ecommunity_ecom2str (rfg->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt both %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } @@ -4492,14 +4492,14 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp) if (rfg->rt_import_list) { char *b = ecommunity_ecom2str (rfg->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt import %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } if (rfg->rt_export_list) { char *b = ecommunity_ecom2str (rfg->rt_export_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt export %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } @@ -4570,7 +4570,7 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp) hc->default_rt_export_list)) { char *b = ecommunity_ecom2str (hc->default_rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt both %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } @@ -4579,14 +4579,14 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp) if (hc->default_rt_import_list) { char *b = ecommunity_ecom2str (hc->default_rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt import %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } if (hc->default_rt_export_list) { char *b = ecommunity_ecom2str (hc->default_rt_export_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt export %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 3cf09e240e..56ca25a131 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -3809,7 +3809,7 @@ DEFUN (debug_rfapi_show_import, for (it = h->imports; it; it = it->next) { s = ecommunity_ecom2str (it->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, "Import Table %p, RTs: %s%s", it, s, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, s); diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 9ae3311e15..3601e06d54 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -1091,8 +1091,8 @@ rfapiEcommunitiesIntersect (struct ecommunity *e1, struct ecommunity *e2) { char *s1, *s2; - s1 = ecommunity_ecom2str (e1, ECOMMUNITY_FORMAT_DISPLAY); - s2 = ecommunity_ecom2str (e2, ECOMMUNITY_FORMAT_DISPLAY); + s1 = ecommunity_ecom2str (e1, ECOMMUNITY_FORMAT_DISPLAY, ECOMMUNITY_ROUTE_TARGET); + s2 = ecommunity_ecom2str (e2, ECOMMUNITY_FORMAT_DISPLAY, ECOMMUNITY_ROUTE_TARGET); vnc_zlog_debug_verbose ("%s: e1[%s], e2[%s]", __func__, s1, s2); XFREE (MTYPE_ECOMMUNITY_STR, s1); XFREE (MTYPE_ECOMMUNITY_STR, s2); diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 521c2319b2..dbc2a430bc 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -484,7 +484,7 @@ rfapi_vty_out_vncinfo ( if (bi->attr && bi->attr->extra && bi->attr->extra->ecommunity) { s = ecommunity_ecom2str (bi->attr->extra->ecommunity, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " EC{%s}", s); XFREE (MTYPE_ECOMMUNITY_STR, s); } @@ -688,7 +688,7 @@ rfapiPrintBi (void *stream, struct bgp_info *bi) if (bi->attr->extra->ecommunity) { s = ecommunity_ecom2str (bi->attr->extra->ecommunity, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); r = snprintf (p, REMAIN, " %s", s); INCP; XFREE (MTYPE_ECOMMUNITY_STR, s); @@ -1445,7 +1445,7 @@ rfapiShowRemoteRegistrationsIt ( } s = ecommunity_ecom2str (it->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); if (pLni) { @@ -1819,7 +1819,7 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd) { s = ecommunity_ecom2str (rfd->rt_export_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " Export %s%s", s, HVTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, s); } @@ -1832,7 +1832,7 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd) if (rfd->import_table) { s = ecommunity_ecom2str (rfd->import_table->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " Import %s%s", s, HVTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, s); } From 4fadf88120b3080938b2250c64c3265c3146fb0e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 7 Oct 2016 18:26:33 +0200 Subject: [PATCH 24/64] tests: update ecommunity_ecom2str call api Test adaptation using updated API, introducing new ecommunity type. Signed-off-by: Philippe Guibert --- tests/bgpd/test_ecommunity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bgpd/test_ecommunity.c b/tests/bgpd/test_ecommunity.c index 9166af6142..9174191cb3 100644 --- a/tests/bgpd/test_ecommunity.c +++ b/tests/bgpd/test_ecommunity.c @@ -97,10 +97,10 @@ validate (struct ecommunity *ecom, const struct test_spec *sp) char *str1, *str2; printf ("got:\n %s\n", ecommunity_str (ecom)); - str1 = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST); + str1 = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0); etmp = ecommunity_str2com (str1, 0, 1); if (etmp) - str2 = ecommunity_ecom2str (etmp, ECOMMUNITY_FORMAT_COMMUNITY_LIST); + str2 = ecommunity_ecom2str (etmp, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0); else str2 = NULL; From aee875b537e946b03d4ab866196f7be4df9bb05e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 10 Aug 2016 10:46:53 +0200 Subject: [PATCH 25/64] bgpd: introduction of vxlan tunnel attribute As per draft-ietf-idr-tunnel-encaps-02, section 3.2.1, BGP Encap attribute supports vxlan tunnel type. A new tunnel attribute has been appended to subtlv list, describing the vxlan network identifier to be used for the routing information of the BGP update message. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr.c | 5 +++-- bgpd/bgp_encap_tlv.c | 22 ++++++++++++++++++++++ bgpd/bgp_encap_types.h | 7 ++++++- bgpd/bgp_route.c | 12 ++++++++++++ bgpd/bgp_route.h | 1 + 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 70d8ffbcc7..3a3cefda59 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -3390,8 +3390,9 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); } - if ((afi == AFI_IP || afi == AFI_IP6) && - (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN)) + if (((afi == AFI_IP || afi == AFI_IP6) && + (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN)) || + (afi == AFI_L2VPN && safi == SAFI_EVPN)) { /* Tunnel Encap attribute */ bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP); diff --git a/bgpd/bgp_encap_tlv.c b/bgpd/bgp_encap_tlv.c index 5c18629aa6..8c5ab8d6f6 100644 --- a/bgpd/bgp_encap_tlv.c +++ b/bgpd/bgp_encap_tlv.c @@ -391,8 +391,30 @@ bgp_encap_type_vxlan_to_tlv( struct attr *attr) { struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *tlv; + uint32_t vnid; extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN; + + if(bet == NULL ||!bet->vnid) + return; + if(extra->encap_subtlvs) + XFREE(MTYPE_ENCAP_TLV, extra->encap_subtlvs); + tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+12); + tlv->type = 1; /* encapsulation type */ + tlv->length = 12; + if(bet->vnid) + { + vnid = htonl(bet->vnid | VXLAN_ENCAP_MASK_VNID_VALID); + memcpy(&tlv->value, &vnid, 4); + } + if(bet->mac_address) + { + char *ptr = (char *)&tlv->value + 4; + memcpy( ptr, bet->mac_address, 6); + } + extra->encap_subtlvs = tlv; + return; } void diff --git a/bgpd/bgp_encap_types.h b/bgpd/bgp_encap_types.h index 0985446ff2..04c0d2f235 100644 --- a/bgpd/bgp_encap_types.h +++ b/bgpd/bgp_encap_types.h @@ -167,10 +167,15 @@ struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode { struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ }; +#define VXLAN_ENCAP_MASK_VNID_VALID 0x80000000 +#define VXLAN_ENCAP_MASK_MAC_VALID 0x40000000 + struct bgp_encap_type_vxlan { uint32_t valid_subtlvs; struct bgp_tea_subtlv_remote_endpoint st_endpoint; /* optional */ - /* No subtlvs defined in spec? */ + /* draft-ietf-idr-tunnel-encaps-02 */ + uint32_t vnid; /* does not include V and M bit */ + uint8_t *mac_address; /* optional */ }; struct bgp_encap_type_nvgre { diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f80c24dcba..8487284edb 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -68,8 +68,11 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/rfapi/vnc_import_bgp.h" #include "bgpd/rfapi/vnc_export_bgp.h" #endif +#include "bgpd/bgp_encap_types.h" +#include "bgpd/bgp_encap_tlv.h" #include "bgpd/bgp_evpn.h" + /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; @@ -4002,7 +4005,16 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); if(afi == AFI_L2VPN) + { overlay_index_update(&attr, bgp_static->eth_s_id, NULL); + if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) + { + struct bgp_encap_type_vxlan bet; + memset(&bet, 0, sizeof(struct bgp_encap_type_vxlan)); + bet.vnid = p->u.prefix_evpn.eth_tag; + bgp_encap_type_vxlan_to_tlv(&bet, &attr); + } + } /* Apply route-map. */ if (bgp_static->rmap.name) { diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 243c5afb00..20465fbf00 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -207,6 +207,7 @@ struct bgp_static /* EVPN */ struct eth_segment_id *eth_s_id; char *router_mac; + uint16_t encap_tunneltype; }; #define BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen) \ From a2dac1ef6a4f0dc3cc4e2bac83700119ff8b7459 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 20 Jan 2017 10:48:42 +0100 Subject: [PATCH 26/64] bgpd: add EVPN RT5 gatewayIp address to bgp_static context This field can be either IPv4 or IPv6 address and is filled in in bgp_static configuration structure. Signed-off-by: Philippe Guibert --- bgpd/bgp_route.c | 7 ++++++- bgpd/bgp_route.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 8487284edb..f924476677 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3993,6 +3993,7 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, #if ENABLE_BGP_VNC u_int32_t label = 0; #endif + union gw_addr add; assert (bgp_static); @@ -4006,7 +4007,11 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, if(afi == AFI_L2VPN) { - overlay_index_update(&attr, bgp_static->eth_s_id, NULL); + if (bgp_static->gatewayIp.family == AF_INET) + add.ipv4.s_addr = bgp_static->gatewayIp.u.prefix4.s_addr; + else if (bgp_static->gatewayIp.family == AF_INET6) + memcpy( &(add.ipv6), &(bgp_static->gatewayIp.u.prefix6), sizeof (struct in6_addr)); + overlay_index_update(&attr, bgp_static->eth_s_id, &add); if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) { struct bgp_encap_type_vxlan bet; diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 20465fbf00..85a8cea860 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -208,6 +208,7 @@ struct bgp_static struct eth_segment_id *eth_s_id; char *router_mac; uint16_t encap_tunneltype; + struct prefix gatewayIp; }; #define BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen) \ From dfa42ea338db2d3bec31d69544fb941bb1822594 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 5 Sep 2016 13:20:41 +0200 Subject: [PATCH 27/64] bgpd: handling router mac extended community For each received routermac extended community, the mac address is copied into routermac extended community context. For each emission, a check is done against routermac extended community, if L2VPN is enabled. If enabled, the extended community is appended. Signed-off-by: Philippe Gubiert --- bgpd/bgp_attr_evpn.c | 20 ++++++++++++++++++++ bgpd/bgp_attr_evpn.h | 3 +++ bgpd/bgp_ecommunity.c | 2 +- bgpd/bgp_route.c | 4 ++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 76c0e51198..a85ba002db 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -27,7 +27,27 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "memory.h" #include "stream.h" +#include "bgpd/bgpd.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" #include "bgpd/bgp_attr_evpn.h" +#include "bgpd/bgp_ecommunity.h" + +void bgp_add_routermac_ecom (struct attr* attr, char * routermac) +{ + struct ecommunity_val routermac_ecom; + + if(attr->extra) + { + memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); + routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; + routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; + memcpy(&routermac_ecom.val[2], routermac, MAC_LEN); + if(!attr->extra->ecommunity) + attr->extra->ecommunity = ecommunity_new (); + ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom); + } +} static uint8_t convertchartohexa (uint8_t *hexa, int *error) { diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 1e8ad3801c..6a779aefbf 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -33,6 +33,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define MAX_ET 0xffffffff u_long eth_tag_id; +struct attr; struct eth_segment_id { @@ -58,4 +59,6 @@ extern char *esi2str (struct eth_segment_id *id); extern char *mac2str (char *mac); extern char *ecom_mac2str(char *ecom_mac); +extern void bgp_add_routermac_ecom (struct attr* attr, char * routermac); + #endif /* _QUAGGA_BGP_ATTR_EVPN_H */ diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 2ea62bbb6d..a5949728c2 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -213,7 +213,7 @@ ecommunity_intern (struct ecommunity *ecom) find->refcnt++; if (! find->str) - find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY, 0); + find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY, ECOMMUNITY_ROUTE_TARGET); return find; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f924476677..8d513fa1dc 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4019,6 +4019,10 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, bet.vnid = p->u.prefix_evpn.eth_tag; bgp_encap_type_vxlan_to_tlv(&bet, &attr); } + if (bgp_static->router_mac) + { + bgp_add_routermac_ecom (&attr, bgp_static->router_mac); + } } /* Apply route-map. */ if (bgp_static->rmap.name) From 784d3a4299eef5f663bb6da4b6e52bf6a6e17d68 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 9 Jan 2017 18:26:24 +0100 Subject: [PATCH 28/64] bgpd: enhance EPVN vty show commands This patch introduces show show bgp evpn commands to dump NLRI entries configured or received on BGP, related to EVPN New command introduced is the following: show [ip] bgp l2vpn evpn [all | rd ] [overlay] Like for MPLS, similar set of commands is added for EVPN: show [ip] bgp l2vpn evpn [all|rd ] show [ip] bgp l2vpn evpn all neighbor routes show [ip] bgp l2vpn evpn all neighbor advertised-routes Signed-off-by: Philippe Guibert --- bgpd/Makefile.am | 4 +- bgpd/bgp_evpn_vty.c | 597 ++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_evpn_vty.h | 27 ++ bgpd/bgp_mplsvpn.c | 177 +------------ bgpd/bgp_mplsvpn.h | 3 +- bgpd/bgp_route.c | 89 ++++++- bgpd/bgp_route.h | 3 + bgpd/bgp_vpn.c | 200 +++++++++++++++ bgpd/bgp_vpn.h | 30 +++ bgpd/bgpd.c | 2 + 10 files changed, 955 insertions(+), 177 deletions(-) create mode 100644 bgpd/bgp_evpn_vty.c create mode 100644 bgpd/bgp_evpn_vty.h create mode 100644 bgpd/bgp_vpn.c create mode 100644 bgpd/bgp_vpn.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 4ce2cd03b5..a9e709e231 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -80,7 +80,7 @@ libbgp_a_SOURCES = \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \ - bgp_evpn.c + bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c noinst_HEADERS = \ bgp_memory.h \ @@ -91,7 +91,7 @@ noinst_HEADERS = \ bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \ bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \ - $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h + $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h bgp_vpn.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c new file mode 100644 index 0000000000..9016f530bc --- /dev/null +++ b/bgpd/bgp_evpn_vty.c @@ -0,0 +1,597 @@ +/* Ethernet-VPN Packet and vty Processing File + Copyright (C) 2017 6WIND + +This file is part of Free Range Routing + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include +#include "command.h" +#include "prefix.h" +#include "lib/json.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_vpn.h" +#include "bgpd/bgp_evpn_vty.h" + +#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n" +#define EVPN_HELP_STR "Ethernet Virtual Private Network\n" + +#define SHOW_DISPLAY_STANDARD 0 +#define SHOW_DISPLAY_TAGS 1 +#define SHOW_DISPLAY_OVERLAY 2 + +static int +bgp_show_ethernet_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type, + void *output_arg, int option, u_char use_json) +{ + afi_t afi = AFI_L2VPN; + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_info *ri; + int rd_header; + int header = 1; + char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + char v4_header_tag[] = " Network Next Hop In tag/Out tag%s"; + char v4_header_overlay[] = " Network Next Hop EthTag Overlay Index RouterMac%s"; + + unsigned long output_count = 0; + unsigned long total_count = 0; + json_object *json = NULL; + json_object *json_nroute = NULL; + json_object *json_array = NULL; + json_object *json_scode = NULL; + json_object *json_ocode = NULL; + + bgp = bgp_get_default (); + if (bgp == NULL) + { + if (!use_json) + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (use_json) + { + json_scode = json_object_new_object(); + json_ocode = json_object_new_object(); + json = json_object_new_object(); + json_nroute = json_object_new_object(); + + json_object_string_add(json_scode, "suppressed", "s"); + json_object_string_add(json_scode, "damped", "d"); + json_object_string_add(json_scode, "history", "h"); + json_object_string_add(json_scode, "valid", "*"); + json_object_string_add(json_scode, "best", ">"); + json_object_string_add(json_scode, "internal", "i"); + + json_object_string_add(json_ocode, "igp", "i"); + json_object_string_add(json_ocode, "egp", "e"); + json_object_string_add(json_ocode, "incomplete", "?"); + } + + for (rn = bgp_table_top (bgp->rib[afi][SAFI_EVPN]); rn; rn = bgp_route_next (rn)) + { + if (use_json) + continue; /* XXX json TODO */ + + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + rd_header = 1; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + for (ri = rm->info; ri; ri = ri->next) + { + total_count++; + if (type == bgp_show_type_neighbor) + { + union sockunion *su = output_arg; + + if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) + continue; + } + if (header == 0) + { + if (use_json) + { + if (option == SHOW_DISPLAY_TAGS) + { + json_object_int_add(json, "bgpTableVersion", 0); + json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id)); + json_object_object_add(json, "bgpStatusCodes", json_scode); + json_object_object_add(json, "bgpOriginCodes", json_ocode); + } + } + else + { + if (option == SHOW_DISPLAY_TAGS) + vty_out (vty, v4_header_tag, VTY_NEWLINE); + else if (option == SHOW_DISPLAY_OVERLAY) + vty_out (vty, v4_header_overlay, VTY_NEWLINE); + else + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, v4_header, VTY_NEWLINE); + } + } + header = 0; + } + if (rd_header) + { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; + + pnt = rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type (pnt); + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as (pnt + 2, &rd_as); + else if (type == RD_TYPE_AS4) + decode_rd_as4 (pnt + 2, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip (pnt + 2, &rd_ip); + if (use_json) + { + char buffer[BUFSIZ]; + if (type == RD_TYPE_AS || type == RD_TYPE_AS4) + sprintf (buffer, "%u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + json_object_string_add(json_nroute, "routeDistinguisher", buffer); + } + else + { + vty_out (vty, "Route Distinguisher: "); + if (type == RD_TYPE_AS) + vty_out (vty, "as2 %u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_AS4) + vty_out (vty, "as4 %u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + vty_out (vty, "ip %s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + vty_out (vty, "%s", VTY_NEWLINE); + } + rd_header = 0; + } + if (use_json) + json_array = json_object_new_array(); + else + json_array = NULL; + if (option == SHOW_DISPLAY_TAGS) + route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_EVPN, json_array); + else if (option == SHOW_DISPLAY_OVERLAY) + route_vty_out_overlay (vty, &rm->p, ri, 0, json_array); + else + route_vty_out (vty, &rm->p, ri, 0, SAFI_EVPN, json_array); + output_count++; + } + /* XXX json */ + } + } + if (output_count == 0) + vty_out (vty, "No prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE); + else + vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s", + VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN (show_ip_bgp_l2vpn_evpn, + show_ip_bgp_l2vpn_evpn_cmd, + "show [ip] bgp l2vpn evpn [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + JSON_STR) +{ + return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, 0, use_json (argc, argv)); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_rd, + show_ip_bgp_l2vpn_evpn_rd_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + JSON_STR) +{ + int idx_ext_community = 6; + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_normal, NULL, 0, use_json (argc, argv)); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_all_tags, + show_ip_bgp_l2vpn_evpn_all_tags_cmd, + "show [ip] bgp l2vpn evpn all tags", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Display BGP tags for prefixes\n") +{ + return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, 1, 0); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_rd_tags, + show_ip_bgp_l2vpn_evpn_rd_tags_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn tags", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Display BGP tags for prefixes\n") +{ + int idx_ext_community = 6; + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_ethernet_vpn (vty,&prd, bgp_show_type_normal, NULL, 1, 0); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_all_neighbor_routes, + show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd, + "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n" + JSON_STR) +{ + int idx_ipv4 = 6; + union sockunion su; + struct peer *peer; + int ret; + u_char uj = use_json(argc, argv); + + ret = str2sockunion (argv[idx_ipv4]->arg, &su); + if (ret < 0) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed address"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "Malformed address: %s%s", argv[idx_ipv4]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "No such neighbor or address family"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_neighbor, &su, 0, uj); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, + show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n" + JSON_STR) +{ + int idx_ext_community = 6; + int idx_ipv4 = 8; + int ret; + union sockunion su; + struct peer *peer; + struct prefix_rd prd; + u_char uj = use_json(argc, argv); + + ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + if (! ret) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed Route Distinguisher"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2sockunion (argv[idx_ipv4]->arg, &su); + if (ret < 0) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed address"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "Malformed address: %s%s", argv[idx_ext_community]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "No such neighbor or address family"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_neighbor, &su, 0, uj); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes, + show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd, + "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n" + JSON_STR) +{ + int idx_ipv4 = 7; + int ret; + struct peer *peer; + union sockunion su; + u_char uj = use_json(argc, argv); + + ret = str2sockunion (argv[idx_ipv4]->arg, &su); + if (ret < 0) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed address"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "Malformed address: %s%s", argv[idx_ipv4]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "No such neighbor or address family"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_vpn (vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, uj); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, + show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n" + JSON_STR) +{ + int idx_ext_community = 6; + int idx_ipv4 = 8; + int ret; + struct peer *peer; + struct prefix_rd prd; + union sockunion su; + u_char uj = use_json(argc, argv); + + ret = str2sockunion (argv[idx_ipv4]->arg, &su); + if (ret < 0) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed address"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "Malformed address: %s%s", argv[idx_ext_community]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup (NULL, &su); + if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "No such neighbor or address family"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + if (! ret) + { + if (uj) + { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", "Malformed Route Distinguisher"); + vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); + json_object_free(json_no); + } + else + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return show_adj_route_vpn (vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj); +} + +DEFUN (show_ip_bgp_l2vpn_evpn_all_overlay, + show_ip_bgp_l2vpn_evpn_all_overlay_cmd, + "show [ip] bgp l2vpn evpn all overlay", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Display BGP Overlay Information for prefixes\n") +{ + return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, + SHOW_DISPLAY_OVERLAY, use_json (argc, argv)); +} + +DEFUN (show_ip_bgp_evpn_rd_overlay, + show_ip_bgp_evpn_rd_overlay_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn overlay", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Display BGP Overlay Information for prefixes\n") +{ + int idx_ext_community = 6; + int ret; + struct prefix_rd prd; + + ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); + if (! ret) + { + vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_normal, NULL, + SHOW_DISPLAY_OVERLAY, use_json (argc, argv)); +} + + +void +bgp_ethernetvpn_init (void) +{ + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd); + install_element (VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd); + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd); +} diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h new file mode 100644 index 0000000000..367a4bd20d --- /dev/null +++ b/bgpd/bgp_evpn_vty.h @@ -0,0 +1,27 @@ +/* EVPN VTY functions to EVPN + Copyright (C) 2017 6WIND + +This file is part of Free Range Routing. + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _FRR_BGP_EVPN_VTY_H +#define _FRR_BGP_EVPN_VTY_H + +extern void +bgp_ethernetvpn_init (void); + +#endif /* _QUAGGA_BGP_EVPN_VTY_H */ diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 3e11e522fa..5fd322b65e 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_vty.h" +#include "bgpd/bgp_vpn.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -146,7 +147,7 @@ decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) #if ENABLE_BGP_VNC /* type == RD_TYPE_VNC_ETH */ -static void +void decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth) { rd_vnc_eth->type = RD_TYPE_VNC_ETH; @@ -550,175 +551,6 @@ DEFUN (no_vpnv6_network, return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg); } -#if defined(KEEP_OLD_VPN_COMMANDS) -static int -show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u_char use_json, afi_t afi) -{ - struct bgp *bgp; - struct bgp_table *table; - struct bgp_node *rn; - struct bgp_node *rm; - struct attr *attr; - int rd_header; - int header = 1; - char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; - json_object *json = NULL; - json_object *json_scode = NULL; - json_object *json_ocode = NULL; - json_object *json_routes = NULL; - json_object *json_array = NULL; - - bgp = bgp_get_default (); - if (bgp == NULL) - { - if (!use_json) - vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (use_json) - { - json_scode = json_object_new_object(); - json_ocode = json_object_new_object(); - json_routes = json_object_new_object(); - json = json_object_new_object(); - - json_object_string_add(json_scode, "suppressed", "s"); - json_object_string_add(json_scode, "damped", "d"); - json_object_string_add(json_scode, "history", "h"); - json_object_string_add(json_scode, "valid", "*"); - json_object_string_add(json_scode, "best", ">"); - json_object_string_add(json_scode, "internal", "i"); - - json_object_string_add(json_ocode, "igp", "i"); - json_object_string_add(json_ocode, "egp", "e"); - json_object_string_add(json_ocode, "incomplete", "?"); - } - - for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn; - rn = bgp_route_next (rn)) - { - if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) - continue; - - if ((table = rn->info) != NULL) - { - if (use_json) - json_array = json_object_new_array(); - else - json_array = NULL; - - rd_header = 1; - - for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) - { - if ((attr = rm->info) != NULL) - { - if (header) - { - if (use_json) - { - json_object_int_add(json, "bgpTableVersion", 0); - json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id)); - json_object_object_add(json, "bgpStatusCodes", json_scode); - json_object_object_add(json, "bgpOriginCodes", json_ocode); - } - else - { - vty_out (vty, "BGP table version is 0, local router ID is %s%s", - inet_ntoa (bgp->router_id), VTY_NEWLINE); - vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", - VTY_NEWLINE); - vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", - VTY_NEWLINE, VTY_NEWLINE); - vty_out (vty, v4_header, VTY_NEWLINE); - } - header = 0; - } - - if (rd_header) - { - u_int16_t type; - struct rd_as rd_as; - struct rd_ip rd_ip = {0}; -#if ENABLE_BGP_VNC - struct rd_vnc_eth rd_vnc_eth = {0}; -#endif - u_char *pnt; - - pnt = rn->p.u.val; - - /* Decode RD type. */ - type = decode_rd_type (pnt); - /* Decode RD value. */ - if (type == RD_TYPE_AS) - decode_rd_as (pnt + 2, &rd_as); - else if (type == RD_TYPE_AS4) - decode_rd_as4 (pnt + 2, &rd_as); - else if (type == RD_TYPE_IP) - decode_rd_ip (pnt + 2, &rd_ip); -#if ENABLE_BGP_VNC - else if (type == RD_TYPE_VNC_ETH) - decode_rd_vnc_eth (pnt, &rd_vnc_eth); -#endif - - if (use_json) - { - char buffer[BUFSIZ]; - if (type == RD_TYPE_AS || type == RD_TYPE_AS4) - sprintf (buffer, "%u:%d", rd_as.as, rd_as.val); - else if (type == RD_TYPE_IP) - sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); - json_object_string_add(json_routes, "routeDistinguisher", buffer); - } - else - { - vty_out (vty, "Route Distinguisher: "); - - if (type == RD_TYPE_AS || type == RD_TYPE_AS4) - vty_out (vty, "%u:%d", rd_as.as, rd_as.val); - else if (type == RD_TYPE_IP) - vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); -#if ENABLE_BGP_VNC - else if (type == RD_TYPE_VNC_ETH) - vty_out (vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x", - rd_vnc_eth.local_nve_id, - rd_vnc_eth.macaddr.octet[0], - rd_vnc_eth.macaddr.octet[1], - rd_vnc_eth.macaddr.octet[2], - rd_vnc_eth.macaddr.octet[3], - rd_vnc_eth.macaddr.octet[4], - rd_vnc_eth.macaddr.octet[5]); -#endif - - vty_out (vty, "%s", VTY_NEWLINE); - } - rd_header = 0; - } - route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN, use_json, json_array); - } - } - if (use_json) - { - struct prefix *p; - char buf_a[BUFSIZ]; - char buf_b[BUFSIZ]; - p = &rm->p; - sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen); - json_object_object_add(json_routes, buf_a, json_array); - } - } - } - if (use_json) - { - json_object_object_add(json, "routes", json_routes); - vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); - json_object_free(json); - } - return CMD_SUCCESS; -} -#endif - int bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, int tags, u_char use_json) @@ -1281,8 +1113,7 @@ DEFUN (show_ip_bgp_vpn_all_neighbor_advertised_routes, vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } - - return show_adj_route_vpn (vty, peer, NULL, uj, afi); + return show_adj_route_vpn (vty, peer, NULL, AFI_IP, SAFI_MPLS_VPN, uj); } return CMD_SUCCESS; } @@ -1360,7 +1191,7 @@ DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes, return CMD_WARNING; } - return show_adj_route_vpn (vty, peer, &prd, uj, afi); + return show_adj_route_vpn (vty, peer, &prd, AFI_IP, SAFI_MPLS_VPN, uj); } return CMD_SUCCESS; } diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 148e5946f1..518bf6143f 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -100,7 +100,8 @@ extern void decode_rd_as (u_char *, struct rd_as *); extern void decode_rd_as4 (u_char *, struct rd_as *); extern void decode_rd_ip (u_char *, struct rd_ip *); #if ENABLE_BGP_VNC -extern void decode_vnc_eth (u_char *, struct rd_vnc_eth *); +extern void +decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth); #endif extern int str2prefix_rd (const char *, struct prefix_rd *); extern int str2tag (const char *, u_char *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 8d513fa1dc..7aee689d9c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6374,7 +6374,7 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, json_object *json_out = NULL; struct attr *attr; u_int32_t label = 0; - + if (!binfo->extra) return; @@ -6464,10 +6464,97 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, else { vty_out (vty, "notag/%d", label); + vty_out (vty, "%s", VTY_NEWLINE); } } +void +route_vty_out_overlay (struct vty *vty, struct prefix *p, + struct bgp_info *binfo, int display, json_object *json_paths) +{ + struct attr *attr; + char buf[BUFSIZ]; + json_object *json_path = NULL; + + if (json_paths) + json_path = json_object_new_object(); + + if (!binfo->extra) + return; + + /* short status lead text */ + route_vty_short_status_out (vty, binfo, json_path); + + /* print prefix and mask */ + if (! display) + route_vty_out_route (p, vty); + else + vty_out (vty, "%*s", 17, " "); + + /* Print attribute */ + attr = binfo->attr; + if (attr) + { + if (attr->extra) + { + char buf1[BUFSIZ]; + int af = NEXTHOP_FAMILY(attr->extra->mp_nexthop_len); + + switch (af) { + case AF_INET: + vty_out (vty, "%-16s", inet_ntop(af, + &attr->extra->mp_nexthop_global_in, buf, BUFSIZ)); + break; + case AF_INET6: + vty_out (vty, "%s(%s)", + inet_ntop (af, + &attr->extra->mp_nexthop_global, buf, BUFSIZ), + inet_ntop (af, + &attr->extra->mp_nexthop_local, buf1, BUFSIZ)); + break; + default: + vty_out(vty, "?"); + } + } else { + vty_out(vty, "?"); + } + } + + if(attr->extra) + { + struct eth_segment_id *id = &(attr->extra->evpn_overlay.eth_s_id); + char *str = esi2str(id); + vty_out (vty, "%s", str); + free(str); + if (p->u.prefix_evpn.flags & IP_PREFIX_V4) + { + vty_out (vty, "/%s", inet_ntoa (attr->extra->evpn_overlay.gw_ip.ipv4)); + } + else if (p->u.prefix_evpn.flags & IP_PREFIX_V6) + { + vty_out (vty, "/%s", + inet_ntop (AF_INET6, &(attr->extra->evpn_overlay.gw_ip.ipv6), + buf, BUFSIZ)); + } + if(attr->extra->ecommunity) + { + char *mac = NULL; + struct ecommunity_val *routermac = ecommunity_lookup (attr->extra->ecommunity, + ECOMMUNITY_ENCODE_EVPN, + ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC); + if(routermac) + mac = ecom_mac2str((char *)routermac->val); + if(mac) + { + vty_out (vty, "/%s",(char *)mac); + free(mac); + } + } + } + vty_out (vty, "%s", VTY_NEWLINE); +} + /* dampening route */ static void damp_route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo, diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 85a8cea860..1f9586d343 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -358,6 +358,9 @@ extern safi_t bgp_node_safi (struct vty *); extern void route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t, json_object *); extern void route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t, json_object *); extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t, u_char, json_object *); +extern void +route_vty_out_overlay (struct vty *vty, struct prefix *p, + struct bgp_info *binfo, int display, json_object *json); extern int subgroup_process_announce_selected (struct update_subgroup *subgrp, diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c new file mode 100644 index 0000000000..edc5891d22 --- /dev/null +++ b/bgpd/bgp_vpn.c @@ -0,0 +1,200 @@ +/* VPN Related functions + Copyright (C) 2017 6WIND + +This file is part of Free Range Routing + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include +#include "command.h" +#include "prefix.h" +#include "lib/json.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_mplsvpn.h" +#include "bgpd/bgp_vpn.h" + +int +show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, + afi_t afi, safi_t safi, u_char use_json) +{ + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct attr *attr; + int rd_header; + int header = 1; + char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; + json_object *json = NULL; + json_object *json_scode = NULL; + json_object *json_ocode = NULL; + json_object *json_routes = NULL; + json_object *json_array = NULL; + + bgp = bgp_get_default (); + if (bgp == NULL) + { + if (!use_json) + vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (use_json) + { + json_scode = json_object_new_object(); + json_ocode = json_object_new_object(); + json_routes = json_object_new_object(); + json = json_object_new_object(); + + json_object_string_add(json_scode, "suppressed", "s"); + json_object_string_add(json_scode, "damped", "d"); + json_object_string_add(json_scode, "history", "h"); + json_object_string_add(json_scode, "valid", "*"); + json_object_string_add(json_scode, "best", ">"); + json_object_string_add(json_scode, "internal", "i"); + + json_object_string_add(json_ocode, "igp", "i"); + json_object_string_add(json_ocode, "egp", "e"); + json_object_string_add(json_ocode, "incomplete", "?"); + } + + for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn; + rn = bgp_route_next (rn)) + { + if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) + continue; + + if ((table = rn->info) != NULL) + { + if (use_json) + json_array = json_object_new_array(); + else + json_array = NULL; + + rd_header = 1; + + for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) + { + if ((attr = rm->info) != NULL) + { + if (header) + { + if (use_json) + { + json_object_int_add(json, "bgpTableVersion", 0); + json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id)); + json_object_object_add(json, "bgpStatusCodes", json_scode); + json_object_object_add(json, "bgpOriginCodes", json_ocode); + } + else + { + vty_out (vty, "BGP table version is 0, local router ID is %s%s", + inet_ntoa (bgp->router_id), VTY_NEWLINE); + vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, v4_header, VTY_NEWLINE); + } + header = 0; + } + + if (rd_header) + { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip = {0}; +#if ENABLE_BGP_VNC + struct rd_vnc_eth rd_vnc_eth = {0}; +#endif + u_char *pnt; + + pnt = rn->p.u.val; + + /* Decode RD type. */ + type = decode_rd_type (pnt); + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as (pnt + 2, &rd_as); + else if (type == RD_TYPE_AS4) + decode_rd_as4 (pnt + 2, &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip (pnt + 2, &rd_ip); +#if ENABLE_BGP_VNC + else if (type == RD_TYPE_VNC_ETH) + decode_rd_vnc_eth (pnt, &rd_vnc_eth); +#endif + + if (use_json) + { + char buffer[BUFSIZ]; + if (type == RD_TYPE_AS || type == RD_TYPE_AS4) + sprintf (buffer, "%u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); + json_object_string_add(json_routes, "routeDistinguisher", buffer); + } + else + { + vty_out (vty, "Route Distinguisher: "); + + if (type == RD_TYPE_AS || type == RD_TYPE_AS4) + vty_out (vty, "%u:%d", rd_as.as, rd_as.val); + else if (type == RD_TYPE_IP) + vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); +#if ENABLE_BGP_VNC + else if (type == RD_TYPE_VNC_ETH) + vty_out (vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x", + rd_vnc_eth.local_nve_id, + rd_vnc_eth.macaddr.octet[0], + rd_vnc_eth.macaddr.octet[1], + rd_vnc_eth.macaddr.octet[2], + rd_vnc_eth.macaddr.octet[3], + rd_vnc_eth.macaddr.octet[4], + rd_vnc_eth.macaddr.octet[5]); +#endif + + vty_out (vty, "%s", VTY_NEWLINE); + } + rd_header = 0; + } + route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN, use_json, json_array); + } + } + if (use_json) + { + struct prefix *p; + char buf_a[BUFSIZ]; + char buf_b[BUFSIZ]; + p = &rm->p; + sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen); + json_object_object_add(json_routes, buf_a, json_array); + } + } + } + if (use_json) + { + json_object_object_add(json, "routes", json_routes); + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } + return CMD_SUCCESS; +} + diff --git a/bgpd/bgp_vpn.h b/bgpd/bgp_vpn.h new file mode 100644 index 0000000000..a16914b65e --- /dev/null +++ b/bgpd/bgp_vpn.h @@ -0,0 +1,30 @@ +/* VPN common functions to MP-BGP + Copyright (C) 2017 6WIND + +This file is part of Free Range Routing. + +Free Range Routing is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +Free Range Routing is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Free Range Routing; see the file COPYING. If not, write to the Free +Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef _FRR_BGP_VPN_H +#define _FRR_BGP_VPN_H + +#include + +extern int +show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, + afi_t afi, safi_t safi, u_char use_json); + +#endif /* _QUAGGA_BGP_VPN_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 5e43400237..627d019523 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -78,6 +78,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_memory.h" +#include "bgpd/bgp_evpn_vty.h" DEFINE_QOBJ_TYPE(bgp_master) DEFINE_QOBJ_TYPE(bgp) @@ -7625,6 +7626,7 @@ bgp_init (void) #if ENABLE_BGP_VNC rfapi_init (); #endif + bgp_ethernetvpn_init (); /* Access list initialize. */ access_list_init (); From dc49391e3605756121de147d0557a7d4ef54a09c Mon Sep 17 00:00:00 2001 From: Julien Courtat Date: Tue, 18 Oct 2016 11:05:26 +0200 Subject: [PATCH 29/64] bgpd: fix display of ethernet vpn route prefix in vty L2VPN route prefix are composed of ethtag, mac address and ip address. vty command "show bgp l2vpn rd <>" show macip prefix in the following template: [ethtag][macaddress/len][ipaddress/len] Signed-off-by: Julien Courtat e --- bgpd/bgp_route.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7aee689d9c..9145a9af73 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5886,6 +5886,11 @@ route_vty_out_route (struct prefix *p, struct vty *vty) else len += vty_out (vty, "/%d", p->prefixlen); } + else if (p->family == AF_ETHERNET) + { + prefix2str(p, buf, PREFIX_STRLEN); + len = vty_out (vty, "%s", buf); + } else len = vty_out (vty, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); @@ -7837,11 +7842,15 @@ route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, } else { + if (p->family == AF_ETHERNET) + prefix2str (p, buf2, INET6_ADDRSTRLEN); + else + inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN); vty_out (vty, "BGP routing table entry for %s%s%s/%d%s", ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) ? prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) ? ":" : "", - inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN), + buf2, p->prefixlen, VTY_NEWLINE); } From 4c63a661e367cdbb16edbdaff50a804428027dcc Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 28 Sep 2016 18:54:17 +0200 Subject: [PATCH 30/64] bgpd: vty commands added for EVPN address family Enhancement of the following show vty evpn commands: show bgp l2vpn evpn all A.B.C.D Signed-off-by: Philippe Guibert --- bgpd/bgp_evpn_vty.c | 3 --- bgpd/bgp_evpn_vty.h | 4 ++++ bgpd/bgp_route.c | 25 +++++++++++++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 9016f530bc..862d0ff92b 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -31,9 +31,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_vpn.h" #include "bgpd/bgp_evpn_vty.h" -#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n" -#define EVPN_HELP_STR "Ethernet Virtual Private Network\n" - #define SHOW_DISPLAY_STANDARD 0 #define SHOW_DISPLAY_TAGS 1 #define SHOW_DISPLAY_OVERLAY 2 diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h index 367a4bd20d..ed654d90b2 100644 --- a/bgpd/bgp_evpn_vty.h +++ b/bgpd/bgp_evpn_vty.h @@ -24,4 +24,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA extern void bgp_ethernetvpn_init (void); +#define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n" +#define EVPN_HELP_STR "Ethernet Virtual Private Network\n" + + #endif /* _QUAGGA_BGP_EVPN_VTY_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9145a9af73..d5d5546a8d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -9269,7 +9269,27 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix, } #endif /* KEEP_OLD_VPN_COMMANDS */ -static void +DEFUN (show_ip_bgp_l2vpn_evpn_all_route_prefix, + show_ip_bgp_l2vpn_evpn_all_route_prefix_cmd, + "show [ip] bgp l2vpn evpn all [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Network in the BGP routing table to display\n" + "Network in the BGP routing table to display\n" + JSON_STR) +{ + int idx = 0; + char *network = NULL; + network = argv_find (argv, argc, "A.B.C.D", &idx) ? argv[idx]->arg : NULL; + network = argv_find (argv, argc, "A.B.C.D/M", &idx) ? argv[idx]->arg : NULL; + return bgp_show_route (vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, 0, BGP_PATH_ALL, use_json(argc, argv)); +} + + static void show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int in, const char *rmap_name, u_char use_json, json_object *json) { @@ -10624,7 +10644,8 @@ bgp_route_init (void) install_element (VIEW_NODE, &show_ip_bgp_vpn_all_route_prefix_cmd); #endif /* KEEP_OLD_VPN_COMMANDS */ install_element (VIEW_NODE, &show_bgp_afi_vpn_rd_route_cmd); - + install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_route_prefix_cmd); + /* BGP dampening clear commands */ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd); From 3da6fcd55711c5226fc2a29738ad886155d94bc5 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 27 Oct 2016 08:02:36 +0200 Subject: [PATCH 31/64] bgpd: enhance network command for evpn route type 5 A new vty command available under evpn address family. This command takes following format: (af-evpn)# [no] network rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip A.B.C.D routermac WORD [route-map WORD] Among new parameters, ethtag stands for the ethernet tag indentifier. ESI stands for the ethernet segment identifier, and must be entered in following format: 00:11:22:33:44:55:66:77:88:99. gwip stands for the gateway IP address contained in RT5 message. A check is done on that value since if gwip is ipv4, then ip prefix must be ipv4. The same for ipv6. RouterMAc is the gateway mac address sent as extended community attribute. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr_evpn.c | 42 ++++++++++++ bgpd/bgp_attr_evpn.h | 2 +- bgpd/bgp_encap.c | 6 +- bgpd/bgp_evpn_vty.c | 68 +++++++++++++++++++ bgpd/bgp_mplsvpn.c | 16 +++-- bgpd/bgp_route.c | 152 ++++++++++++++++++++++++++++++++++++++----- bgpd/bgp_route.h | 6 +- 7 files changed, 265 insertions(+), 27 deletions(-) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index a85ba002db..6f5a5ffc49 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -32,6 +32,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr_evpn.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_evpn.h" void bgp_add_routermac_ecom (struct attr* attr, char * routermac) { @@ -281,3 +282,44 @@ char *ecom_mac2str(char *ecom_mac) en+=2; return mac2str(en); } + +/* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */ +extern int bgp_build_evpn_prefix (int evpn_type, uint32_t eth_tag, struct prefix *dst) +{ +#if defined(HAVE_EVPN) + struct evpn_addr *p_evpn_p; + struct prefix p2; + struct prefix *src = &p2; + + if (!dst || dst->family == 0) + return -1; + /* store initial prefix in src */ + prefix_copy (src, dst); + memset (dst, 0, sizeof (struct prefix)); + p_evpn_p = &(dst->u.prefix_evpn); + dst->family = AF_ETHERNET; + p_evpn_p->route_type = evpn_type; + if (evpn_type == EVPN_IP_PREFIX) + { + p_evpn_p->eth_tag = eth_tag; + p_evpn_p->ip_prefix_length = p2.prefixlen; + if (src->family == AF_INET) + { + p_evpn_p->flags = IP_PREFIX_V4; + memcpy (&p_evpn_p->ip.v4_addr, &src->u.prefix4, sizeof(struct in_addr)); + dst->prefixlen = (u_char)PREFIX_LEN_ROUTE_TYPE_5_IPV4; + } + else + { + p_evpn_p->flags = IP_PREFIX_V6; + memcpy (&p_evpn_p->ip.v6_addr, &src->u.prefix6, sizeof(struct in6_addr)); + dst->prefixlen = (u_char)PREFIX_LEN_ROUTE_TYPE_5_IPV6; + } + } + else + return -1; + return 0; +#else + return -1; +#endif /* !(HAVE_EVPN) */ +} diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 6a779aefbf..89a666ba23 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -60,5 +60,5 @@ extern char *mac2str (char *mac); extern char *ecom_mac2str(char *ecom_mac); extern void bgp_add_routermac_ecom (struct attr* attr, char * routermac); - +extern int bgp_build_evpn_prefix (int type, uint32_t eth_tag, struct prefix *dst); #endif /* _QUAGGA_BGP_ATTR_EVPN_H */ diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c index 72a30220ff..6e021c4e9e 100644 --- a/bgpd/bgp_encap.c +++ b/bgpd/bgp_encap.c @@ -219,7 +219,8 @@ DEFUN (encap_network, int idx_ipv4 = 1; int idx_rd = 3; int idx_word = 5; - return bgp_static_set_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg, NULL); + return bgp_static_set_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg, + NULL, 0, NULL, NULL, NULL, NULL); } /* For testing purpose, static route of ENCAP. */ @@ -237,7 +238,8 @@ DEFUN (no_encap_network, int idx_ipv4 = 2; int idx_rd = 4; int idx_word = 6; - return bgp_static_unset_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg); + return bgp_static_unset_safi (SAFI_ENCAP, vty, argv[idx_ipv4]->arg, argv[idx_rd]->arg, argv[idx_word]->arg, + 0, NULL, NULL, NULL); } static int diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 862d0ff92b..bb144bfe4a 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_vpn.h" #include "bgpd/bgp_evpn_vty.h" +#include "bgpd/bgp_evpn.h" #define SHOW_DISPLAY_STANDARD 0 #define SHOW_DISPLAY_TAGS 1 @@ -577,6 +578,71 @@ DEFUN (show_ip_bgp_evpn_rd_overlay, SHOW_DISPLAY_OVERLAY, use_json (argc, argv)); } +/* For testing purpose, static route of MPLS-VPN. */ +DEFUN (evpnrt5_network, + evpnrt5_network_cmd, + "network rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip routermac WORD [route-map WORD]", + "Specify a network to announce via BGP\n" + "IP prefix\n" + "IPv6 prefix\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "Ethernet Tag\n" + "Ethernet Tag Value\n" + "BGP label\n" + "label value\n" + "Ethernet Segment Identifier\n" + "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n" + "Gateway IP\n" + "Gateway IP ( A.B.C.D )\n" + "Gateway IPv6 ( X:X::X:X )\n" + "Router Mac Ext Comm\n" + "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n") +{ + int idx_ipv4_prefixlen = 1; + int idx_ext_community = 3; + int idx_word = 7; + int idx_esi = 9; + int idx_gwip = 11; + int idx_ethtag = 5; + int idx_routermac = 13; + int idx_rmap = 15; + return bgp_static_set_safi (SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, + argv[idx_word]->arg, argv[idx_rmap]?argv[idx_gwip]->arg:NULL, + EVPN_IP_PREFIX, argv[idx_esi]->arg, argv[idx_gwip]->arg, + argv[idx_ethtag]->arg, argv[idx_routermac]->arg); +} + +/* For testing purpose, static route of MPLS-VPN. */ +DEFUN (no_evpnrt5_network, + no_evpnrt5_network_cmd, + "no network rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip ", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix\n" + "IPv6 prefix\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "Ethernet Tag\n" + "Ethernet Tag Value\n" + "BGP label\n" + "label value\n" + "Ethernet Segment Identifier\n" + "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n" + "Gateway IP\n" + "Gateway IP ( A.B.C.D )\n" + "Gateway IPv6 ( X:X::X:X )\n") +{ + int idx_ipv4_prefixlen = 2; + int idx_ext_community = 4; + int idx_label = 8; + int idx_ethtag = 6; + int idx_esi = 10; + int idx_gwip = 12; + return bgp_static_unset_safi (SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_label]->arg, + EVPN_IP_PREFIX, argv[idx_esi]->arg, argv[idx_gwip]->arg, argv[idx_ethtag]->arg); +} + void bgp_ethernetvpn_init (void) @@ -591,4 +657,6 @@ bgp_ethernetvpn_init (void) install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd); install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd); + install_element (BGP_EVPN_NODE, &no_evpnrt5_network_cmd); + install_element (BGP_EVPN_NODE, &evpnrt5_network_cmd); } diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 5fd322b65e..d29fb26030 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -471,7 +471,8 @@ DEFUN (vpnv4_network, int idx_ipv4_prefixlen = 1; int idx_ext_community = 3; int idx_word = 5; - return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, NULL); + return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, + argv[idx_word]->arg, NULL, 0, NULL, NULL, NULL, NULL); } DEFUN (vpnv4_network_route_map, @@ -490,7 +491,8 @@ DEFUN (vpnv4_network_route_map, int idx_ext_community = 3; int idx_word = 5; int idx_word_2 = 7; - return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_word_2]->arg); + return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, + argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL); } /* For testing purpose, static route of MPLS-VPN. */ @@ -508,7 +510,9 @@ DEFUN (no_vpnv4_network, int idx_ipv4_prefixlen = 2; int idx_ext_community = 4; int idx_word = 6; - return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg); + return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, + argv[idx_ext_community]->arg, argv[idx_word]->arg, + 0, NULL, NULL, NULL); } DEFUN (vpnv6_network, @@ -528,9 +532,9 @@ DEFUN (vpnv6_network, int idx_word = 5; int idx_word_2 = 7; if (argv[idx_word_2]) - return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_word_2]->arg); + return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL); else - return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, NULL); + return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, NULL, 0, NULL, NULL, NULL, NULL); } /* For testing purpose, static route of MPLS-VPN. */ @@ -548,7 +552,7 @@ DEFUN (no_vpnv6_network, int idx_ipv6_prefix = 2; int idx_ext_community = 4; int idx_word = 6; - return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg); + return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, 0, NULL, NULL, NULL); } int diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index d5d5546a8d..6d8336032f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -71,6 +71,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_encap_types.h" #include "bgpd/bgp_encap_tlv.h" #include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_evpn_vty.h" /* Extern from bgp_dump.c */ @@ -4432,7 +4433,8 @@ bgp_purge_static_redist_routes (struct bgp *bgp) int bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, const char *rd_str, const char *tag_str, - const char *rmap_str) + const char *rmap_str, int evpn_type, const char *esi, const char *gwip, + const char *ethtag, const char *routermac) { VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; @@ -4444,7 +4446,14 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, struct bgp_static *bgp_static; u_char tag[3]; afi_t afi; + struct prefix gw_ip; + if(safi == SAFI_EVPN) + afi = AFI_L2VPN; + else + afi = AFI_IP; + + /* validate ip prefix */ ret = str2prefix (ip_str, &p); if (! ret) { @@ -4452,6 +4461,12 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, return CMD_WARNING; } apply_mask (&p); + if ( (afi == AFI_L2VPN) && + (bgp_build_evpn_prefix ( evpn_type, ethtag!=NULL?atol(ethtag):0, &p))) + { + vty_out (vty, "%% L2VPN prefix could not be forged%s", VTY_NEWLINE); + return CMD_WARNING; + } ret = str2prefix_rd (rd_str, &prd); if (! ret) @@ -4460,20 +4475,47 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, return CMD_WARNING; } - ret = str2tag (tag_str, tag); - if (! ret) + if (tag_str) { - vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE); - return CMD_WARNING; + ret = str2tag (tag_str, tag); + if (! ret) + { + vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE); + return CMD_WARNING; + } } - if (p.family == AF_INET) - afi = AFI_IP; - else if (p.family == AF_INET6) - afi = AFI_IP6; else { - vty_out (vty, "%% Non Supported prefix%s", VTY_NEWLINE); - return CMD_WARNING; + encode_label (0, tag); + } + if (safi == SAFI_EVPN) + { + if( esi && str2esi (esi, NULL) == 0) + { + vty_out (vty, "%% Malformed ESI%s", VTY_NEWLINE); + return CMD_WARNING; + } + if( routermac && str2mac (routermac, NULL) == 0) + { + vty_out (vty, "%% Malformed Router MAC%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (gwip) + { + memset (&gw_ip, 0, sizeof (struct prefix)); + ret = str2prefix (gwip, &gw_ip); + if (! ret) + { + vty_out (vty, "%% Malformed GatewayIp%s", VTY_NEWLINE); + return CMD_WARNING; + } + if((gw_ip.family == AF_INET && (p.u.prefix_evpn.flags & IP_PREFIX_V6)) + || (gw_ip.family == AF_INET6 && (p.u.prefix_evpn.flags & IP_PREFIX_V4))) + { + vty_out (vty, "%% GatewayIp family differs with IP prefix%s", VTY_NEWLINE); + return CMD_WARNING; + } + } } prn = bgp_node_get (bgp->route[afi][safi], (struct prefix *)&prd); @@ -4508,6 +4550,22 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, bgp_static->rmap.name = strdup (rmap_str); bgp_static->rmap.map = route_map_lookup_by_name (rmap_str); } + + if (safi == SAFI_EVPN) + { + if(esi) + { + bgp_static->eth_s_id = XCALLOC (MTYPE_ATTR, sizeof(struct eth_segment_id)); + str2esi (esi, bgp_static->eth_s_id); + } + if( routermac) + { + bgp_static->router_mac = XCALLOC (MTYPE_ATTR, MAC_LEN+1); + str2mac (routermac, bgp_static->router_mac); + } + if (gwip) + prefix_copy (&bgp_static->gatewayIp, &gw_ip); + } rn->info = bgp_static; bgp_static->valid = 1; @@ -4520,7 +4578,8 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, /* Configure static BGP network. */ int bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str, - const char *rd_str, const char *tag_str) + const char *rd_str, const char *tag_str, + int evpn_type, const char *esi, const char *gwip, const char *ethtag) { VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; @@ -4531,6 +4590,12 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str, struct bgp_table *table; struct bgp_static *bgp_static; u_char tag[3]; + afi_t afi; + + if(safi == SAFI_EVPN) + afi = AFI_L2VPN; + else + afi = AFI_IP; /* Convert IP prefix string to struct prefix. */ ret = str2prefix (ip_str, &p); @@ -4540,7 +4605,12 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str, return CMD_WARNING; } apply_mask (&p); - + if ( (afi == AFI_L2VPN) && + (bgp_build_evpn_prefix ( evpn_type, ethtag!=NULL?atol(ethtag):0, &p))) + { + vty_out (vty, "%% L2VPN prefix could not be forged%s", VTY_NEWLINE); + return CMD_WARNING; + } ret = str2prefix_rd (rd_str, &prd); if (! ret) { @@ -4555,10 +4625,10 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str, return CMD_WARNING; } - prn = bgp_node_get (bgp->route[AFI_IP][safi], + prn = bgp_node_get (bgp->route[afi][safi], (struct prefix *)&prd); if (prn->info == NULL) - prn->info = bgp_table_init (AFI_IP, safi); + prn->info = bgp_table_init (afi, safi); else bgp_unlock_node (prn); table = prn->info; @@ -4567,7 +4637,7 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str, if (rn) { - bgp_static_withdraw_safi (bgp, &p, AFI_IP, safi, &prd, tag); + bgp_static_withdraw_safi (bgp, &p, afi, safi, &prd, tag); bgp_static = rn->info; bgp_static_free (bgp_static); @@ -10427,6 +10497,53 @@ bgp_config_write_network_vpn (struct vty *vty, struct bgp *bgp, return 0; } +static int +bgp_config_write_network_evpn (struct vty *vty, struct bgp *bgp, + afi_t afi, safi_t safi, int *write) +{ + struct bgp_node *prn; + struct bgp_node *rn; + struct bgp_table *table; + struct prefix *p; + struct prefix_rd *prd; + struct bgp_static *bgp_static; + char buf[PREFIX_STRLEN]; + char buf2[SU_ADDRSTRLEN]; + char rdbuf[RD_ADDRSTRLEN]; + + /* Network configuration. */ + for (prn = bgp_table_top (bgp->route[afi][safi]); prn; prn = bgp_route_next (prn)) + if ((table = prn->info) != NULL) + for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) + if ((bgp_static = rn->info) != NULL) + { + char *macrouter = NULL; + char *esi = NULL; + + if(bgp_static->router_mac) + macrouter = mac2str(bgp_static->router_mac); + if(bgp_static->eth_s_id) + esi = esi2str(bgp_static->eth_s_id); + p = &rn->p; + prd = (struct prefix_rd *) &prn->p; + + /* "address-family" display. */ + bgp_config_write_family_header (vty, afi, safi, write); + + /* "network" configuration display. */ + prefix_rd2str (prd, rdbuf, RD_ADDRSTRLEN); + + inet_ntop (AF_INET, &bgp_static->igpnexthop, buf2, SU_ADDRSTRLEN); + + prefix2str (p, buf, sizeof (buf)), + vty_out (vty, " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s", + buf, rdbuf, p->u.prefix_evpn.eth_tag, + decode_label (bgp_static->tag), esi, buf2 , macrouter); + vty_out (vty, "%s", VTY_NEWLINE); + } + return 0; +} + /* Configuration of static route announcement and aggregate information. */ int @@ -10442,6 +10559,9 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp, if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) return bgp_config_write_network_vpn (vty, bgp, afi, safi, write); + if (afi == AFI_L2VPN && safi == SAFI_EVPN) + return bgp_config_write_network_evpn (vty, bgp, afi, safi, write); + /* Network configuration. */ for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if ((bgp_static = rn->info) != NULL) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 1f9586d343..da015feb21 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -319,10 +319,12 @@ extern void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static extern void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t); extern int bgp_static_set_safi (safi_t safi, struct vty *vty, const char *, - const char *, const char *, const char *); + const char *, const char *, const char *, + int, const char *, const char *, const char *, const char *); extern int bgp_static_unset_safi (safi_t safi, struct vty *, const char *, - const char *, const char *); + const char *, const char *, + int, const char *, const char *, const char *); /* this is primarily for MPLS-VPN */ extern int bgp_update (struct peer *, struct prefix *, u_int32_t, struct attr *, From 061e9fdea56b6078b68ab23191449abd92aa71cf Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 20 Jan 2017 14:02:49 +0100 Subject: [PATCH 32/64] bgpd: update mp_nexthop field in case mp-bgp entry is created In case a manual set of MPLS, ENCAP, or EVPN entry is set, then the nexthop attribute localted in attr->extra structure must be changed too. In standard cases, where IPv4 IGP nexthop address is picked up, the same address ie chosen. Signed-off-by: Philippe Guibert --- bgpd/bgp_route.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 6d8336032f..e303cbb644 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4006,6 +4006,14 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, attr.med = bgp_static->igpmetric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + if ((safi == SAFI_EVPN) || (safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)) + { + if (bgp_static->igpnexthop.s_addr) + { + bgp_attr_extra_get (&attr)->mp_nexthop_global_in = bgp_static->igpnexthop; + bgp_attr_extra_get (&attr)->mp_nexthop_len = IPV4_MAX_BYTELEN; + } + } if(afi == AFI_L2VPN) { if (bgp_static->gatewayIp.family == AF_INET) From b94c6c502675bee2be543c1ba1253fb0c7a6105d Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 20 Jan 2017 18:47:23 +0100 Subject: [PATCH 33/64] bgpd: fix show bgp l2vpn evpn all tag command This commit fixes the nexthop display behaviour when an evpn entry is matched. The commit handles both cases where IPv4 or IPv6 nexthop is detected. Signed-off-by: Philippe Guibert --- bgpd/bgp_route.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e303cbb644..085763ba81 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4137,7 +4137,6 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, /* Register new BGP information. */ bgp_info_add (rn, new); - /* route_node_get lock */ bgp_unlock_node (rn); @@ -6480,8 +6479,9 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, attr = binfo->attr; if (attr) { - if (p->family == AF_INET - && (safi == SAFI_MPLS_VPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) + if (((p->family == AF_INET) && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) + || (safi == SAFI_EVPN && p->family == AF_ETHERNET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) + || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { @@ -6498,7 +6498,9 @@ route_vty_out_tag (struct vty *vty, struct prefix *p, vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } } - else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) + else if (((p->family == AF_INET6) && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) + || (safi == SAFI_EVPN && p->family == AF_ETHERNET && BGP_ATTR_NEXTHOP_AFI_IP6(attr)) + || (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { assert (attr->extra); char buf_a[BUFSIZ]; From 4895ca359525b5242d92793d30ef2eaddee06768 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 17 Jan 2017 22:26:33 +0100 Subject: [PATCH 34/64] bgpd: use HAVE_EVPN to disable evpn frame handling Transmission and Reception routines have a part of code that is conditionnally compiled to the usage of HAVE_EVPN. Also, each time a subfield of prefix evpn is reached, like in configuration also, then a conditionnaly compilation with HAVE_EVPN is used. Signed-off-by: Philippe Guibert --- bgpd/bgp_evpn.c | 7 ++++--- bgpd/bgp_route.c | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a9db7d2360..98661d7c38 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -60,8 +60,7 @@ bgp_nlri_parse_evpn (struct peer *peer, struct attr *attr, #if !defined(HAVE_EVPN) return -1; -#endif /* HAVE_EVPN */ - +#else p_evpn_p = &p.u.prefix_evpn; pnt = packet->nlri; lim = pnt + packet->length; @@ -184,7 +183,7 @@ bgp_nlri_parse_evpn (struct peer *peer, struct attr *attr, /* Packet length consistency check. */ if (pnt != lim) return -1; - +#endif /* !(HAVE_EVPN) */ return 0; } @@ -193,6 +192,7 @@ bgp_packet_mpattr_route_type_5 (struct stream *s, struct prefix *p, struct prefix_rd *prd, u_char *label, struct attr *attr) { +#if defined(HAVE_EVPN) int len; char temp[16]; struct evpn_addr *p_evpn_p; @@ -237,4 +237,5 @@ bgp_packet_mpattr_route_type_5 (struct stream *s, else stream_put3 (s, 0); return; +#endif /* (HAVE_EVPN) */ } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 085763ba81..5f47e88a78 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3994,7 +3994,9 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, #if ENABLE_BGP_VNC u_int32_t label = 0; #endif +#if defined(HAVE_EVPN) union gw_addr add; +#endif /* (HAVE_EVPN) */ assert (bgp_static); @@ -4014,6 +4016,7 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, bgp_attr_extra_get (&attr)->mp_nexthop_len = IPV4_MAX_BYTELEN; } } +#if defined(HAVE_EVPN) if(afi == AFI_L2VPN) { if (bgp_static->gatewayIp.family == AF_INET) @@ -4033,6 +4036,7 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, bgp_add_routermac_ecom (&attr, bgp_static->router_mac); } } +#endif /* (HAVE_EVPN) */ /* Apply route-map. */ if (bgp_static->rmap.name) { @@ -4495,6 +4499,7 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, { encode_label (0, tag); } +#if defined (HAVE_EVPN) if (safi == SAFI_EVPN) { if( esi && str2esi (esi, NULL) == 0) @@ -4524,6 +4529,7 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, } } } +#endif /* (HAVE_EVPN) */ prn = bgp_node_get (bgp->route[afi][safi], (struct prefix *)&prd); if (prn->info == NULL) @@ -6608,6 +6614,7 @@ route_vty_out_overlay (struct vty *vty, struct prefix *p, if(attr->extra) { +#if defined (HAVE_EVPN) struct eth_segment_id *id = &(attr->extra->evpn_overlay.eth_s_id); char *str = esi2str(id); vty_out (vty, "%s", str); @@ -6622,6 +6629,7 @@ route_vty_out_overlay (struct vty *vty, struct prefix *p, inet_ntop (AF_INET6, &(attr->extra->evpn_overlay.gw_ip.ipv6), buf, BUFSIZ)); } +#endif /* (HAVE_EVPN) */ if(attr->extra->ecommunity) { char *mac = NULL; @@ -10546,9 +10554,11 @@ bgp_config_write_network_evpn (struct vty *vty, struct bgp *bgp, inet_ntop (AF_INET, &bgp_static->igpnexthop, buf2, SU_ADDRSTRLEN); prefix2str (p, buf, sizeof (buf)), +#if defined (HAVE_EVPN) vty_out (vty, " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s", buf, rdbuf, p->u.prefix_evpn.eth_tag, decode_label (bgp_static->tag), esi, buf2 , macrouter); +#endif /*(HAVE_EVPN)*/ vty_out (vty, "%s", VTY_NEWLINE); } return 0; From b194703e9c0870b2f4b26b1af259690facfc0489 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 23 Jan 2017 09:28:53 +0100 Subject: [PATCH 35/64] bgpd: remove old address-family vty command for evpn old vty format to configure evpn: address-family evpn is no longer supported. Signed-off-by: Philippe Guibert --- bgpd/bgp_vty.c | 2 +- vtysh/vtysh.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index efcef248a8..4564b9492f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5712,7 +5712,7 @@ DEFUN (address_family_encapv6, DEFUN (address_family_evpn, address_family_evpn_cmd, - "address-family ", + "address-family ", "Enter Address Family command mode\n" "EVPN Address family\n" "Layer2 VPN Address family\n" diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index c68ff50a5c..579c0fc590 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1213,7 +1213,7 @@ DEFUNSH (VTYSH_BGPD, DEFUNSH (VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd, - "address-family ", + "address-family ", "Enter Address Family command mode\n" "EVPN Address family\n" "Layer2 VPN Address family\n" From dd3fb4c3eebe6679413748546ff589e481462e05 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 23 Jan 2017 14:47:35 +0100 Subject: [PATCH 36/64] tests: fix bgp print in tests This commit is a fix from previous commit: Quagga: AFI/SAFI mappings IANA to/from internal values. It removes the printf that was used for troubleshooting the afi/safi change, in respect to testing. Signed-off-by: Philippe Guibert --- tests/bgpd/test_mp_attr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index 96a0e0759d..883cac0cc6 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -729,7 +729,6 @@ parse_test (struct peer *peer, struct test_segment *t, int type) else nlri_ret = bgp_nlri_parse (peer, &attr, &nlri, 1); } - zlog_err("xxxxxxxxxxxxxxxx nlri ret %u", nlri_ret); handle_result (peer, t, parse_ret, nlri_ret); } From ce7e1778a64e7be539ccb9dc614a739e04d893a6 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 23 Jan 2017 15:12:38 +0100 Subject: [PATCH 37/64] bgpd: use a define for addpath string size The define is added in order to be reused, when one wants to display addpath identifier as a string with some comment. Signed-off-by: Philippe Guibert --- bgpd/bgp_debug.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 1292de626d..e1e7cb1d5b 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -40,6 +40,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_mplsvpn.h" +#define BGP_ADDPATH_STR 20 + unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_neighbor_events; unsigned long conf_bgp_debug_events; @@ -2095,7 +2097,7 @@ bgp_debug_rdpfxpath2str (struct prefix_rd *prd, union prefixconstptr pu, { char rd_buf[RD_ADDRSTRLEN]; char pfx_buf[PREFIX_STRLEN]; - char pathid_buf[20]; + char pathid_buf[BGP_ADDPATH_STR]; if (size < BGP_PRD_PATH_STRLEN) return NULL; From cbdc66c7c137d3f8cd0c55510b860040dd6f005b Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 25 Jan 2017 08:43:35 +0100 Subject: [PATCH 38/64] Revert "configure: add enable-evpn support" This reverts commit 764c98c9b45a3f7aa976bc9298c89e210b084fe2. --- configure.ac | 9 --------- 1 file changed, 9 deletions(-) diff --git a/configure.ac b/configure.ac index 83250776f9..1436b2fc7c 100755 --- a/configure.ac +++ b/configure.ac @@ -285,8 +285,6 @@ AC_ARG_ENABLE([protobuf], AS_HELP_STRING([--enable-protobuf], [Enable experimental protobuf support])) AC_ARG_ENABLE([oldvpn_commands], AS_HELP_STRING([--enable-old-vpn-commands], [Keep old vpn commands])) -AC_ARG_ENABLE(evpn, - AS_HELP_STRING([--enable-evpn], [enable EVPN support)])) AC_CHECK_HEADERS(json-c/json.h) AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c") @@ -399,13 +397,6 @@ if test "$enable_old_vpn_commands" = "yes"; then AC_DEFINE(KEEP_OLD_VPN_COMMANDS,, [Define for compiling with old vpn commands]) fi -# Logic for evpn support. -# -if test "$enable_evpn" = "yes"; then - have_evpn=yes - AC_DEFINE(HAVE_EVPN,, [Define for compiling with EVPN]) -fi - # Fail if the user explicity enabled protobuf support and we couldn't # find the compiler or libraries. if test "x$have_protobuf" = "xno" && test "x$enable_protobuf" = "xyes"; then From 0737aa5edb47a14a2ee5b76c4cbe4ced25336e2c Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 25 Jan 2017 08:48:42 +0100 Subject: [PATCH 39/64] lib: remove HAVE_EVPN references This commit removes references to HAVE_EVPN references in lib folder. Signed-off-by: Philippe Guibert --- lib/prefix.c | 6 ------ lib/prefix.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index 514e4f8ebe..1b168abedc 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -304,12 +304,10 @@ prefix_copy (struct prefix *dest, const struct prefix *src) dest->u.prefix4 = src->u.prefix4; else if (src->family == AF_INET6) dest->u.prefix6 = src->u.prefix6; -#if defined(HAVE_EVPN) else if (src->family == AF_ETHERNET) { memcpy (&dest->u.prefix_evpn, &src->u.prefix_evpn, sizeof (struct evpn_addr)); } -#endif /* (HAVE_EVPN) */ else if (src->family == AF_UNSPEC) { dest->u.lp.id = src->u.lp.id; @@ -348,11 +346,9 @@ prefix_same (const struct prefix *p1, const struct prefix *p2) if (p1->family == AF_INET6 ) if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr)) return 1; -#if defined(HAVE_EVPN) if (p1->family == AF_ETHERNET ) if (!memcmp (&p1->u.prefix_evpn, &p2->u.prefix_evpn, sizeof (struct evpn_addr))) return 1; -#endif /* (HAVE_EVPN) */ } return 0; } @@ -873,7 +869,6 @@ prefix2str (union prefixconstptr pu, char *str, int size) p->prefixlen); break; -#if defined(HAVE_EVPN) case AF_ETHERNET: if (p->u.prefix_evpn.route_type == 5) { @@ -888,7 +883,6 @@ prefix2str (union prefixconstptr pu, char *str, int size) p->prefixlen); } break; -#endif /* (HAVE_EVPN) */ default: sprintf (str, "UNK prefix"); break; diff --git a/lib/prefix.h b/lib/prefix.h index 5c1c71a7c0..472dc1a01a 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -119,9 +119,7 @@ struct prefix struct ethaddr prefix_eth; /* AF_ETHERNET */ u_char val[8]; uintptr_t ptr; -#if defined(HAVE_EVPN) struct evpn_addr prefix_evpn; -#endif } u __attribute__ ((aligned (8))); }; From 42362ae230e6a55b876b11d5e72cdb4b24760ca5 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 25 Jan 2017 08:49:19 +0100 Subject: [PATCH 40/64] bgpd: remove HAVE_EVPN references This commit removes HAVE_EVPN references from bgpd folder Signed-off-by: Philippe Guibert --- bgpd/bgp_attr_evpn.c | 4 ---- bgpd/bgp_evpn.c | 6 ------ bgpd/bgp_route.c | 10 ---------- bgpd/bgp_vty.c | 2 -- 4 files changed, 22 deletions(-) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 6f5a5ffc49..26fc08f658 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -286,7 +286,6 @@ char *ecom_mac2str(char *ecom_mac) /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */ extern int bgp_build_evpn_prefix (int evpn_type, uint32_t eth_tag, struct prefix *dst) { -#if defined(HAVE_EVPN) struct evpn_addr *p_evpn_p; struct prefix p2; struct prefix *src = &p2; @@ -319,7 +318,4 @@ extern int bgp_build_evpn_prefix (int evpn_type, uint32_t eth_tag, struct prefix else return -1; return 0; -#else - return -1; -#endif /* !(HAVE_EVPN) */ } diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 98661d7c38..b0b33c0b54 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -58,9 +58,6 @@ bgp_nlri_parse_evpn (struct peer *peer, struct attr *attr, prd.family = AF_UNSPEC; prd.prefixlen = 64; -#if !defined(HAVE_EVPN) - return -1; -#else p_evpn_p = &p.u.prefix_evpn; pnt = packet->nlri; lim = pnt + packet->length; @@ -183,7 +180,6 @@ bgp_nlri_parse_evpn (struct peer *peer, struct attr *attr, /* Packet length consistency check. */ if (pnt != lim) return -1; -#endif /* !(HAVE_EVPN) */ return 0; } @@ -192,7 +188,6 @@ bgp_packet_mpattr_route_type_5 (struct stream *s, struct prefix *p, struct prefix_rd *prd, u_char *label, struct attr *attr) { -#if defined(HAVE_EVPN) int len; char temp[16]; struct evpn_addr *p_evpn_p; @@ -237,5 +232,4 @@ bgp_packet_mpattr_route_type_5 (struct stream *s, else stream_put3 (s, 0); return; -#endif /* (HAVE_EVPN) */ } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 5f47e88a78..085763ba81 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3994,9 +3994,7 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, #if ENABLE_BGP_VNC u_int32_t label = 0; #endif -#if defined(HAVE_EVPN) union gw_addr add; -#endif /* (HAVE_EVPN) */ assert (bgp_static); @@ -4016,7 +4014,6 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, bgp_attr_extra_get (&attr)->mp_nexthop_len = IPV4_MAX_BYTELEN; } } -#if defined(HAVE_EVPN) if(afi == AFI_L2VPN) { if (bgp_static->gatewayIp.family == AF_INET) @@ -4036,7 +4033,6 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p, bgp_add_routermac_ecom (&attr, bgp_static->router_mac); } } -#endif /* (HAVE_EVPN) */ /* Apply route-map. */ if (bgp_static->rmap.name) { @@ -4499,7 +4495,6 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, { encode_label (0, tag); } -#if defined (HAVE_EVPN) if (safi == SAFI_EVPN) { if( esi && str2esi (esi, NULL) == 0) @@ -4529,7 +4524,6 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, } } } -#endif /* (HAVE_EVPN) */ prn = bgp_node_get (bgp->route[afi][safi], (struct prefix *)&prd); if (prn->info == NULL) @@ -6614,7 +6608,6 @@ route_vty_out_overlay (struct vty *vty, struct prefix *p, if(attr->extra) { -#if defined (HAVE_EVPN) struct eth_segment_id *id = &(attr->extra->evpn_overlay.eth_s_id); char *str = esi2str(id); vty_out (vty, "%s", str); @@ -6629,7 +6622,6 @@ route_vty_out_overlay (struct vty *vty, struct prefix *p, inet_ntop (AF_INET6, &(attr->extra->evpn_overlay.gw_ip.ipv6), buf, BUFSIZ)); } -#endif /* (HAVE_EVPN) */ if(attr->extra->ecommunity) { char *mac = NULL; @@ -10554,11 +10546,9 @@ bgp_config_write_network_evpn (struct vty *vty, struct bgp *bgp, inet_ntop (AF_INET, &bgp_static->igpnexthop, buf2, SU_ADDRSTRLEN); prefix2str (p, buf, sizeof (buf)), -#if defined (HAVE_EVPN) vty_out (vty, " network %s rd %s ethtag %u tag %u esi %s gwip %s routermac %s", buf, rdbuf, p->u.prefix_evpn.eth_tag, decode_label (bgp_static->tag), esi, buf2 , macrouter); -#endif /*(HAVE_EVPN)*/ vty_out (vty, "%s", VTY_NEWLINE); } return 0; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 4564b9492f..896518fca3 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5718,9 +5718,7 @@ DEFUN (address_family_evpn, "Layer2 VPN Address family\n" "Ethernet Virtual Private Network Subsequent Address Family\n") { -#if defined(HAVE_EVPN) vty->node = BGP_EVPN_NODE; -#endif /* HAVE_EVPN */ return CMD_SUCCESS; } From 4d0e6ece4bcd2a39d03e6c8d3fe7109601a22286 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 27 Jan 2017 08:25:27 +0100 Subject: [PATCH 41/64] bgpd: indent new evpn code to the frr standards Using intent tool, and apply to all bgp_evpn files. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr_evpn.c | 441 ++++++++-------- bgpd/bgp_attr_evpn.h | 43 +- bgpd/bgp_evpn.c | 358 ++++++------- bgpd/bgp_evpn.h | 12 +- bgpd/bgp_evpn_vty.c | 1194 +++++++++++++++++++++++------------------- bgpd/bgp_evpn_vty.h | 6 +- 6 files changed, 1054 insertions(+), 1000 deletions(-) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 26fc08f658..31f75baa20 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -34,43 +34,42 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_evpn.h" -void bgp_add_routermac_ecom (struct attr* attr, char * routermac) +void bgp_add_routermac_ecom(struct attr *attr, char *routermac) { - struct ecommunity_val routermac_ecom; + struct ecommunity_val routermac_ecom; - if(attr->extra) - { - memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); - routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; - routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; - memcpy(&routermac_ecom.val[2], routermac, MAC_LEN); - if(!attr->extra->ecommunity) - attr->extra->ecommunity = ecommunity_new (); - ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom); - } + if (attr->extra) { + memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); + routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; + routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; + memcpy(&routermac_ecom.val[2], routermac, MAC_LEN); + if (!attr->extra->ecommunity) + attr->extra->ecommunity = ecommunity_new(); + ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom); + } } -static uint8_t convertchartohexa (uint8_t *hexa, int *error) +static uint8_t convertchartohexa(uint8_t * hexa, int *error) { - if( (*hexa == '0') || (*hexa == '1') || (*hexa == '2') || - (*hexa == '3') || (*hexa == '4') || (*hexa == '5') || - (*hexa == '6') || (*hexa == '7') || (*hexa == '8') || - (*hexa == '9')) - return (uint8_t)(*hexa)-'0'; - if((*hexa == 'a') || (*hexa == 'A')) - return 0xa; - if((*hexa == 'b') || (*hexa == 'B')) - return 0xb; - if((*hexa == 'c') || (*hexa == 'C')) - return 0xc; - if((*hexa == 'd') || (*hexa == 'D')) - return 0xd; - if((*hexa == 'e') || (*hexa == 'E')) - return 0xe; - if((*hexa == 'f') || (*hexa == 'F')) - return 0xf; - *error = -1; - return 0; + if ((*hexa == '0') || (*hexa == '1') || (*hexa == '2') || + (*hexa == '3') || (*hexa == '4') || (*hexa == '5') || + (*hexa == '6') || (*hexa == '7') || (*hexa == '8') + || (*hexa == '9')) + return (uint8_t) (*hexa) - '0'; + if ((*hexa == 'a') || (*hexa == 'A')) + return 0xa; + if ((*hexa == 'b') || (*hexa == 'B')) + return 0xb; + if ((*hexa == 'c') || (*hexa == 'C')) + return 0xc; + if ((*hexa == 'd') || (*hexa == 'D')) + return 0xd; + if ((*hexa == 'e') || (*hexa == 'E')) + return 0xe; + if ((*hexa == 'f') || (*hexa == 'F')) + return 0xf; + *error = -1; + return 0; } /* converts to internal representation of mac address @@ -78,81 +77,72 @@ static uint8_t convertchartohexa (uint8_t *hexa, int *error) * format accepted: AA:BB:CC:DD:EE:FF * if mac parameter is null, then check only */ -int -str2mac (const char *str, char *mac) +int str2mac(const char *str, char *mac) { - unsigned int k=0, i, j; - uint8_t *ptr, *ptr2; - size_t len; - uint8_t car; + unsigned int k = 0, i, j; + uint8_t *ptr, *ptr2; + size_t len; + uint8_t car; - if (!str) - return 0; + if (!str) + return 0; - if (str[0] == ':' && str[1] == '\0') - return 1; + if (str[0] == ':' && str[1] == '\0') + return 1; - i = 0; - ptr = (uint8_t *)str; - while (i < 6) - { - uint8_t temp[5]; - int error = 0; - ptr2 = (uint8_t *)strchr((const char *)ptr, ':'); - if (ptr2 == NULL) - { - /* if last occurence return ok */ - if(i != 5) - { - zlog_err("[%s]: format non recognized",mac); - return 0; - } - len = strlen((char *)ptr); - } - else - { - len = ptr2 - ptr; - } - if(len > 5) - { - zlog_err("[%s]: format non recognized",mac); - return 0; - } - memcpy(temp, ptr, len); - for(j=0;j< len;j++) - { - if (k >= MAC_LEN) - return 0; - if(mac) - mac[k] = 0; - car = convertchartohexa (&temp[j], &error); - if (error) - return 0; - if(mac) - mac[k] = car << 4; - j++; - if(j == len) - return 0; - car = convertchartohexa (&temp[j], &error) & 0xf; - if (error) - return 0; - if(mac) - mac[k] |= car & 0xf; - k++; - i++; + i = 0; + ptr = (uint8_t *) str; + while (i < 6) { + uint8_t temp[5]; + int error = 0; + ptr2 = (uint8_t *) strchr((const char *)ptr, ':'); + if (ptr2 == NULL) { + /* if last occurence return ok */ + if (i != 5) { + zlog_err("[%s]: format non recognized", mac); + return 0; + } + len = strlen((char *)ptr); + } else { + len = ptr2 - ptr; + } + if (len > 5) { + zlog_err("[%s]: format non recognized", mac); + return 0; + } + memcpy(temp, ptr, len); + for (j = 0; j < len; j++) { + if (k >= MAC_LEN) + return 0; + if (mac) + mac[k] = 0; + car = convertchartohexa(&temp[j], &error); + if (error) + return 0; + if (mac) + mac[k] = car << 4; + j++; + if (j == len) + return 0; + car = convertchartohexa(&temp[j], &error) & 0xf; + if (error) + return 0; + if (mac) + mac[k] |= car & 0xf; + k++; + i++; + } + ptr = ptr2; + if (ptr == NULL) + break; + ptr++; } - ptr = ptr2; - if(ptr == NULL) - break; - ptr++; - } - if(mac && 0) - { - zlog_err("leave correct : %02x:%02x:%02x:%02x:%02x:%02x", - mac[0] & 0xff, mac[1] & 0xff, mac[2] & 0xff, - mac[3] & 0xff, mac[4] & 0xff, mac[5] & 0xff); - } - return 1; + if (mac && 0) { + zlog_err("leave correct : %02x:%02x:%02x:%02x:%02x:%02x", + mac[0] & 0xff, mac[1] & 0xff, mac[2] & 0xff, + mac[3] & 0xff, mac[4] & 0xff, mac[5] & 0xff); + } + return 1; } /* converts to an esi @@ -160,162 +150,151 @@ str2mac (const char *str, char *mac) * format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ * if id is null, check only is done */ -int -str2esi (const char *str, struct eth_segment_id *id) +int str2esi(const char *str, struct eth_segment_id *id) { - unsigned int k=0, i, j; - uint8_t *ptr, *ptr2; - size_t len; - uint8_t car; + unsigned int k = 0, i, j; + uint8_t *ptr, *ptr2; + size_t len; + uint8_t car; - if (!str) - return 0; - if (str[0] == ':' && str[1] == '\0') - return 1; + if (!str) + return 0; + if (str[0] == ':' && str[1] == '\0') + return 1; - i = 0; - ptr = (uint8_t *)str; - while (i < 10) - { - uint8_t temp[5]; - int error = 0; - ptr2 = (uint8_t *)strchr((const char *)ptr, ':'); - if (ptr2 == NULL) - { - /* if last occurence return ok */ - if(i != 9) - { - zlog_err("[%s]: format non recognized",str); - return 0; - } - len = strlen((char *)ptr); + i = 0; + ptr = (uint8_t *) str; + while (i < 10) { + uint8_t temp[5]; + int error = 0; + ptr2 = (uint8_t *) strchr((const char *)ptr, ':'); + if (ptr2 == NULL) { + /* if last occurence return ok */ + if (i != 9) { + zlog_err("[%s]: format non recognized", str); + return 0; + } + len = strlen((char *)ptr); + } else { + len = ptr2 - ptr; + } + memcpy(temp, ptr, len); + if (len > 5) { + zlog_err("[%s]: format non recognized", str); + return 0; + } + for (j = 0; j < len; j++) { + if (k >= ESI_LEN) + return 0; + if (id) + id->val[k] = 0; + car = convertchartohexa(&temp[j], &error); + if (error) + return 0; + if (id) + id->val[k] = car << 4; + j++; + if (j == len) + return 0; + car = convertchartohexa(&temp[j], &error) & 0xf; + if (error) + return 0; + if (id) + id->val[k] |= car & 0xf; + k++; + i++; + } + ptr = ptr2; + if (ptr == NULL) + break; + ptr++; } - else - { - len = ptr2 - ptr; - } - memcpy(temp, ptr, len); - if(len > 5) - { - zlog_err("[%s]: format non recognized",str); - return 0; - } - for(j=0;j< len;j++) - { - if (k >= ESI_LEN) - return 0; - if(id) - id->val[k] = 0; - car = convertchartohexa (&temp[j], &error); - if (error) - return 0; - if(id) - id->val[k] = car << 4; - j++; - if(j == len) - return 0; - car = convertchartohexa (&temp[j], &error) & 0xf; - if (error) - return 0; - if(id) - id->val[k] |= car & 0xf; - k++; - i++; + if (id && 0) { + zlog_err("leave correct : %02x:%02x:%02x:%02x:%02x", + id->val[0], id->val[1], id->val[2], id->val[3], + id->val[4]); + zlog_err("%02x:%02x:%02x:%02x:%02x", id->val[5], id->val[6], + id->val[7], id->val[8], id->val[9]); } - ptr = ptr2; - if(ptr == NULL) - break; - ptr++; - } - if(id && 0) - { - zlog_err("leave correct : %02x:%02x:%02x:%02x:%02x", - id->val[0], id->val[1], id->val[2], id->val[3], id->val[4]); - zlog_err("%02x:%02x:%02x:%02x:%02x", - id->val[5], id->val[6], id->val[7], id->val[8], id->val[9]); - } - return 1; + return 1; } -char * -esi2str (struct eth_segment_id *id) +char *esi2str(struct eth_segment_id *id) { - char *ptr; - u_char *val; + char *ptr; + u_char *val; - if(!id) - return NULL; + if (!id) + return NULL; - val = id->val; - ptr = (char *) malloc ((ESI_LEN*2+ESI_LEN-1+1)*sizeof(char)); + val = id->val; + ptr = (char *)malloc((ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char)); - snprintf (ptr, (ESI_LEN*2+ESI_LEN-1+1), - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - val[0], val[1], val[2], val[3], val[4], - val[5], val[6], val[7], val[8], val[9]); + snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1), + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + val[0], val[1], val[2], val[3], val[4], + val[5], val[6], val[7], val[8], val[9]); - return ptr; + return ptr; } -char * -mac2str (char *mac) +char *mac2str(char *mac) { - char *ptr; + char *ptr; - if(!mac) - return NULL; + if (!mac) + return NULL; - ptr = (char *) malloc ((MAC_LEN*2+MAC_LEN-1+1)*sizeof(char)); + ptr = (char *)malloc((MAC_LEN * 2 + MAC_LEN - 1 + 1) * sizeof(char)); - snprintf (ptr, (MAC_LEN*2+MAC_LEN-1+1), "%02x:%02x:%02x:%02x:%02x:%02x", - (uint8_t) mac[0], (uint8_t)mac[1], (uint8_t)mac[2], (uint8_t)mac[3], - (uint8_t)mac[4], (uint8_t)mac[5]); + snprintf(ptr, (MAC_LEN * 2 + MAC_LEN - 1 + 1), + "%02x:%02x:%02x:%02x:%02x:%02x", (uint8_t) mac[0], + (uint8_t) mac[1], (uint8_t) mac[2], (uint8_t) mac[3], + (uint8_t) mac[4], (uint8_t) mac[5]); - return ptr; + return ptr; } char *ecom_mac2str(char *ecom_mac) { - char *en; + char *en; - en = ecom_mac; - en+=2; - return mac2str(en); + en = ecom_mac; + en += 2; + return mac2str(en); } /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */ -extern int bgp_build_evpn_prefix (int evpn_type, uint32_t eth_tag, struct prefix *dst) +extern int +bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, struct prefix *dst) { - struct evpn_addr *p_evpn_p; - struct prefix p2; - struct prefix *src = &p2; + struct evpn_addr *p_evpn_p; + struct prefix p2; + struct prefix *src = &p2; - if (!dst || dst->family == 0) - return -1; - /* store initial prefix in src */ - prefix_copy (src, dst); - memset (dst, 0, sizeof (struct prefix)); - p_evpn_p = &(dst->u.prefix_evpn); - dst->family = AF_ETHERNET; - p_evpn_p->route_type = evpn_type; - if (evpn_type == EVPN_IP_PREFIX) - { - p_evpn_p->eth_tag = eth_tag; - p_evpn_p->ip_prefix_length = p2.prefixlen; - if (src->family == AF_INET) - { - p_evpn_p->flags = IP_PREFIX_V4; - memcpy (&p_evpn_p->ip.v4_addr, &src->u.prefix4, sizeof(struct in_addr)); - dst->prefixlen = (u_char)PREFIX_LEN_ROUTE_TYPE_5_IPV4; - } - else - { - p_evpn_p->flags = IP_PREFIX_V6; - memcpy (&p_evpn_p->ip.v6_addr, &src->u.prefix6, sizeof(struct in6_addr)); - dst->prefixlen = (u_char)PREFIX_LEN_ROUTE_TYPE_5_IPV6; - } - } - else - return -1; - return 0; + if (!dst || dst->family == 0) + return -1; + /* store initial prefix in src */ + prefix_copy(src, dst); + memset(dst, 0, sizeof(struct prefix)); + p_evpn_p = &(dst->u.prefix_evpn); + dst->family = AF_ETHERNET; + p_evpn_p->route_type = evpn_type; + if (evpn_type == EVPN_IP_PREFIX) { + p_evpn_p->eth_tag = eth_tag; + p_evpn_p->ip_prefix_length = p2.prefixlen; + if (src->family == AF_INET) { + p_evpn_p->flags = IP_PREFIX_V4; + memcpy(&p_evpn_p->ip.v4_addr, &src->u.prefix4, + sizeof(struct in_addr)); + dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4; + } else { + p_evpn_p->flags = IP_PREFIX_V6; + memcpy(&p_evpn_p->ip.v6_addr, &src->u.prefix6, + sizeof(struct in6_addr)); + dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV6; + } + } else + return -1; + return 0; } diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 89a666ba23..aff0ae4141 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -22,12 +22,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define _QUAGGA_BGP_ATTR_EVPN_H /* value of first byte of ESI */ -#define ESI_TYPE_ARBITRARY 0 /* */ -#define ESI_TYPE_LACP 1 /* <> */ -#define ESI_TYPE_BRIDGE 2 /* ::00 */ -#define ESI_TYPE_MAC 3 /* : */ -#define ESI_TYPE_ROUTER 4 /* : */ -#define ESI_TYPE_AS 5 /* : */ +#define ESI_TYPE_ARBITRARY 0 /* */ +#define ESI_TYPE_LACP 1 /* <> */ +#define ESI_TYPE_BRIDGE 2 /* ::00 */ +#define ESI_TYPE_MAC 3 /* : */ +#define ESI_TYPE_ROUTER 4 /* : */ +#define ESI_TYPE_AS 5 /* : */ #define MAX_ESI {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff} #define ESI_LEN 10 @@ -35,30 +35,29 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA u_long eth_tag_id; struct attr; -struct eth_segment_id -{ - u_char val[ESI_LEN]; +struct eth_segment_id { + u_char val[ESI_LEN]; }; #define MAC_LEN 6 union gw_addr { - struct in_addr ipv4; - struct in6_addr ipv6; + struct in_addr ipv4; + struct in6_addr ipv6; }; -struct bgp_route_evpn -{ - struct eth_segment_id eth_s_id; - union gw_addr gw_ip; +struct bgp_route_evpn { + struct eth_segment_id eth_s_id; + union gw_addr gw_ip; }; -extern int str2esi (const char *str, struct eth_segment_id *id); -extern int str2mac (const char *str, char *mac); -extern char *esi2str (struct eth_segment_id *id); -extern char *mac2str (char *mac); +extern int str2esi(const char *str, struct eth_segment_id *id); +extern int str2mac(const char *str, char *mac); +extern char *esi2str(struct eth_segment_id *id); +extern char *mac2str(char *mac); extern char *ecom_mac2str(char *ecom_mac); -extern void bgp_add_routermac_ecom (struct attr* attr, char * routermac); -extern int bgp_build_evpn_prefix (int type, uint32_t eth_tag, struct prefix *dst); -#endif /* _QUAGGA_BGP_ATTR_EVPN_H */ +extern void bgp_add_routermac_ecom(struct attr *attr, char *routermac); +extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, + struct prefix *dst); +#endif /* _QUAGGA_BGP_ATTR_EVPN_H */ diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index b0b33c0b54..b9acbbed08 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -18,7 +18,6 @@ along with Free Range Routing; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - #include #include "command.h" @@ -37,199 +36,190 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_evpn.h" int -bgp_nlri_parse_evpn (struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, int withdraw) +bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw) { - u_char *pnt; - u_char *lim; - struct prefix p; - struct prefix_rd prd; - struct evpn_addr *p_evpn_p; - struct bgp_route_evpn evpn; - uint8_t route_type, route_length; - u_char *pnt_label; - u_int32_t addpath_id = 0; + u_char *pnt; + u_char *lim; + struct prefix p; + struct prefix_rd prd; + struct evpn_addr *p_evpn_p; + struct bgp_route_evpn evpn; + uint8_t route_type, route_length; + u_char *pnt_label; + u_int32_t addpath_id = 0; - /* Check peer status. */ - if (peer->status != Established) - return 0; - - /* Make prefix_rd */ - prd.family = AF_UNSPEC; - prd.prefixlen = 64; + /* Check peer status. */ + if (peer->status != Established) + return 0; - p_evpn_p = &p.u.prefix_evpn; - pnt = packet->nlri; - lim = pnt + packet->length; - while (pnt < lim) - { - /* clear evpn structure */ - memset (&evpn, 0, sizeof (evpn)); + /* Make prefix_rd */ + prd.family = AF_UNSPEC; + prd.prefixlen = 64; - /* Clear prefix structure. */ - memset (&p, 0, sizeof (struct prefix)); - memset(&evpn.gw_ip, 0, sizeof(union gw_addr)); - memset(&evpn.eth_s_id, 0, sizeof(struct eth_segment_id)); + p_evpn_p = &p.u.prefix_evpn; + pnt = packet->nlri; + lim = pnt + packet->length; + while (pnt < lim) { + /* clear evpn structure */ + memset(&evpn, 0, sizeof(evpn)); - /* Fetch Route Type */ - route_type = *pnt++; - route_length = *pnt++; - /* simply ignore. goto next route type if any */ - if(route_type != EVPN_IP_PREFIX) - { - if (pnt + route_length > lim) - { - zlog_err ("not enough bytes for New Route Type left in NLRI?"); - return -1; - } - pnt += route_length; - continue; + /* Clear prefix structure. */ + memset(&p, 0, sizeof(struct prefix)); + memset(&evpn.gw_ip, 0, sizeof(union gw_addr)); + memset(&evpn.eth_s_id, 0, sizeof(struct eth_segment_id)); + + /* Fetch Route Type */ + route_type = *pnt++; + route_length = *pnt++; + /* simply ignore. goto next route type if any */ + if (route_type != EVPN_IP_PREFIX) { + if (pnt + route_length > lim) { + zlog_err + ("not enough bytes for New Route Type left in NLRI?"); + return -1; + } + pnt += route_length; + continue; + } + + /* Fetch RD */ + if (pnt + 8 > lim) { + zlog_err("not enough bytes for RD left in NLRI?"); + return -1; + } + + /* Copy routing distinguisher to rd. */ + memcpy(&prd.val, pnt, 8); + pnt += 8; + + /* Fetch ESI */ + if (pnt + 10 > lim) { + zlog_err("not enough bytes for ESI left in NLRI?"); + return -1; + } + memcpy(&evpn.eth_s_id.val, pnt, 10); + pnt += 10; + + /* Fetch Ethernet Tag */ + if (pnt + 4 > lim) { + zlog_err("not enough bytes for Eth Tag left in NLRI?"); + return -1; + } + + if (route_type == EVPN_IP_PREFIX) { + p_evpn_p->route_type = route_type; + memcpy(&(p_evpn_p->eth_tag), pnt, 4); + p_evpn_p->eth_tag = ntohl(p_evpn_p->eth_tag); + pnt += 4; + + /* Fetch IP prefix length. */ + p_evpn_p->ip_prefix_length = *pnt++; + + if (p_evpn_p->ip_prefix_length > 128) { + zlog_err("invalid prefixlen %d in EVPN NLRI?", + p.prefixlen); + return -1; + } + /* determine IPv4 or IPv6 prefix */ + if (route_length - 4 - 10 - 8 - + 3 /* label to be read */ >= 32) { + p_evpn_p->flags = IP_PREFIX_V6; + memcpy(&(p_evpn_p->ip.v4_addr), pnt, 16); + pnt += 16; + memcpy(&evpn.gw_ip.ipv6, pnt, 16); + pnt += 16; + } else { + p_evpn_p->flags = IP_PREFIX_V4; + memcpy(&(p_evpn_p->ip.v4_addr), pnt, 4); + pnt += 4; + memcpy(&evpn.gw_ip.ipv4, pnt, 4); + pnt += 4; + } + p.family = AFI_L2VPN; + if (p_evpn_p->flags == IP_PREFIX_V4) + p.prefixlen = + (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4; + else + p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6; + p.family = AF_ETHERNET; + } + + /* Fetch Label */ + if (pnt + 3 > lim) { + zlog_err("not enough bytes for Label left in NLRI?"); + return -1; + } + pnt_label = pnt; + + pnt += 3; + + if (!withdraw) { + bgp_update(peer, &p, addpath_id, attr, AFI_L2VPN, + SAFI_EVPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + &prd, pnt_label, 0, &evpn); + } else { + bgp_withdraw(peer, &p, addpath_id, attr, AFI_L2VPN, + SAFI_EVPN, ZEBRA_ROUTE_BGP, + BGP_ROUTE_NORMAL, &prd, pnt_label, &evpn); + } } - /* Fetch RD */ - if (pnt + 8 > lim) - { - zlog_err ("not enough bytes for RD left in NLRI?"); - return -1; - } - - /* Copy routing distinguisher to rd. */ - memcpy (&prd.val, pnt, 8); - pnt += 8; - - /* Fetch ESI */ - if (pnt + 10 > lim) - { - zlog_err ("not enough bytes for ESI left in NLRI?"); - return -1; - } - memcpy(&evpn.eth_s_id.val, pnt, 10); - pnt += 10; - - /* Fetch Ethernet Tag */ - if (pnt + 4 > lim) - { - zlog_err ("not enough bytes for Eth Tag left in NLRI?"); - return -1; - } - - if (route_type == EVPN_IP_PREFIX) - { - p_evpn_p->route_type = route_type; - memcpy (&(p_evpn_p->eth_tag), pnt, 4); - p_evpn_p->eth_tag = ntohl(p_evpn_p->eth_tag); - pnt += 4; - - /* Fetch IP prefix length. */ - p_evpn_p->ip_prefix_length = *pnt++; - - if (p_evpn_p->ip_prefix_length > 128) - { - zlog_err ("invalid prefixlen %d in EVPN NLRI?", p.prefixlen); - return -1; - } - /* determine IPv4 or IPv6 prefix */ - if(route_length - 4 - 10 - 8 - 3 /* label to be read */ >= 32) - { - p_evpn_p->flags = IP_PREFIX_V6; - memcpy (&(p_evpn_p->ip.v4_addr), pnt, 16); - pnt += 16; - memcpy(&evpn.gw_ip.ipv6, pnt, 16); - pnt += 16; - } - else - { - p_evpn_p->flags = IP_PREFIX_V4; - memcpy (&(p_evpn_p->ip.v4_addr), pnt, 4); - pnt += 4; - memcpy(&evpn.gw_ip.ipv4, pnt, 4); - pnt += 4; - } - p.family = AFI_L2VPN; - if (p_evpn_p->flags == IP_PREFIX_V4) - p.prefixlen = (u_char)PREFIX_LEN_ROUTE_TYPE_5_IPV4; - else - p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6; - p.family = AF_ETHERNET; - } - - /* Fetch Label */ - if (pnt + 3 > lim) - { - zlog_err ("not enough bytes for Label left in NLRI?"); - return -1; - } - pnt_label = pnt; - - pnt += 3; - - if (!withdraw) - { - bgp_update (peer, &p, addpath_id, attr, AFI_L2VPN, SAFI_EVPN, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, - pnt_label, 0, &evpn); - } - else - { - bgp_withdraw (peer, &p, addpath_id, attr, AFI_L2VPN, SAFI_EVPN, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, - &prd, pnt_label, &evpn); - } - } - - /* Packet length consistency check. */ - if (pnt != lim) - return -1; - return 0; + /* Packet length consistency check. */ + if (pnt != lim) + return -1; + return 0; } void -bgp_packet_mpattr_route_type_5 (struct stream *s, - struct prefix *p, struct prefix_rd *prd, - u_char *label, struct attr *attr) +bgp_packet_mpattr_route_type_5(struct stream *s, + struct prefix *p, struct prefix_rd *prd, + u_char * label, struct attr *attr) { - int len; - char temp[16]; - struct evpn_addr *p_evpn_p; + int len; + char temp[16]; + struct evpn_addr *p_evpn_p; - memset(&temp, 0, 16); - if(p->family != AF_ETHERNET) - return; - p_evpn_p = &(p->u.prefix_evpn); - if (p_evpn_p->flags & IP_PREFIX_V4) - len = 8; /* ipv4 */ - else - len = 32; /* ipv6 */ - stream_putc (s, EVPN_IP_PREFIX); - stream_putc (s, 8 /* RD */ + 10 /* ESI */ + 4 /* EthTag */ + 1 + len + 3 /* label */); - stream_put (s, prd->val, 8); - if(attr && attr->extra) - stream_put (s, &(attr->extra->evpn_overlay.eth_s_id), 10); - else - stream_put (s, &temp, 10); - stream_putl (s, p_evpn_p->eth_tag); - stream_putc (s, p_evpn_p->ip_prefix_length); - if (p_evpn_p->flags & IP_PREFIX_V4) - stream_put_ipv4(s, p_evpn_p->ip.v4_addr.s_addr); - else - stream_put(s, &p_evpn_p->ip.v6_addr, 16); - if(attr && attr->extra) - { - if (p_evpn_p->flags & IP_PREFIX_V4) - stream_put_ipv4(s, attr->extra->evpn_overlay.gw_ip.ipv4.s_addr); - else - stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6), 16); - } - else - { - if (p_evpn_p->flags & IP_PREFIX_V4) - stream_put_ipv4(s, 0); - else - stream_put(s, &temp, 16); - } - if(label) - stream_put (s, label, 3); - else - stream_put3 (s, 0); - return; + memset(&temp, 0, 16); + if (p->family != AF_ETHERNET) + return; + p_evpn_p = &(p->u.prefix_evpn); + if (p_evpn_p->flags & IP_PREFIX_V4) + len = 8; /* ipv4 */ + else + len = 32; /* ipv6 */ + stream_putc(s, EVPN_IP_PREFIX); + stream_putc(s, + 8 /* RD */ + 10 /* ESI */ + 4 /* EthTag */ + 1 + len + + 3 /* label */ ); + stream_put(s, prd->val, 8); + if (attr && attr->extra) + stream_put(s, &(attr->extra->evpn_overlay.eth_s_id), 10); + else + stream_put(s, &temp, 10); + stream_putl(s, p_evpn_p->eth_tag); + stream_putc(s, p_evpn_p->ip_prefix_length); + if (p_evpn_p->flags & IP_PREFIX_V4) + stream_put_ipv4(s, p_evpn_p->ip.v4_addr.s_addr); + else + stream_put(s, &p_evpn_p->ip.v6_addr, 16); + if (attr && attr->extra) { + if (p_evpn_p->flags & IP_PREFIX_V4) + stream_put_ipv4(s, + attr->extra->evpn_overlay.gw_ip.ipv4. + s_addr); + else + stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6), + 16); + } else { + if (p_evpn_p->flags & IP_PREFIX_V4) + stream_put_ipv4(s, 0); + else + stream_put(s, &temp, 16); + } + if (label) + stream_put(s, label, 3); + else + stream_put3(s, 0); + return; } diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index d23509304b..63c1a766ea 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -21,13 +21,13 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _QUAGGA_BGP_EVPN_H #define _QUAGGA_BGP_EVPN_H -extern int bgp_nlri_parse_evpn (struct peer *peer, struct attr *attr, - struct bgp_nlri *packet, int withdraw); +extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw); extern void -bgp_packet_mpattr_route_type_5 (struct stream *s, - struct prefix *p, struct prefix_rd *prd, - u_char *label, struct attr *attr); +bgp_packet_mpattr_route_type_5(struct stream *s, + struct prefix *p, struct prefix_rd *prd, + u_char * label, struct attr *attr); /* EVPN route types as per RFC7432 and * as per draft-ietf-bess-evpn-prefix-advertisement-02 */ @@ -37,4 +37,4 @@ bgp_packet_mpattr_route_type_5 (struct stream *s, #define EVPN_ETHERNET_SEGMENT 4 #define EVPN_IP_PREFIX 5 -#endif /* _QUAGGA_BGP_EVPN_H */ +#endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index bb144bfe4a..ed67a61f69 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -37,626 +37,714 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define SHOW_DISPLAY_OVERLAY 2 static int -bgp_show_ethernet_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type, - void *output_arg, int option, u_char use_json) +bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, + enum bgp_show_type type, void *output_arg, int option, + u_char use_json) { - afi_t afi = AFI_L2VPN; - struct bgp *bgp; - struct bgp_table *table; - struct bgp_node *rn; - struct bgp_node *rm; - struct bgp_info *ri; - int rd_header; - int header = 1; - char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; - char v4_header_tag[] = " Network Next Hop In tag/Out tag%s"; - char v4_header_overlay[] = " Network Next Hop EthTag Overlay Index RouterMac%s"; + afi_t afi = AFI_L2VPN; + struct bgp *bgp; + struct bgp_table *table; + struct bgp_node *rn; + struct bgp_node *rm; + struct bgp_info *ri; + int rd_header; + int header = 1; + char v4_header[] = + " Network Next Hop Metric LocPrf Weight Path%s"; + char v4_header_tag[] = + " Network Next Hop In tag/Out tag%s"; + char v4_header_overlay[] = + " Network Next Hop EthTag Overlay Index RouterMac%s"; - unsigned long output_count = 0; - unsigned long total_count = 0; - json_object *json = NULL; - json_object *json_nroute = NULL; - json_object *json_array = NULL; - json_object *json_scode = NULL; - json_object *json_ocode = NULL; + unsigned long output_count = 0; + unsigned long total_count = 0; + json_object *json = NULL; + json_object *json_nroute = NULL; + json_object *json_array = NULL; + json_object *json_scode = NULL; + json_object *json_ocode = NULL; - bgp = bgp_get_default (); - if (bgp == NULL) - { - if (!use_json) - vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); - return CMD_WARNING; - } + bgp = bgp_get_default(); + if (bgp == NULL) { + if (!use_json) + vty_out(vty, "No BGP process is configured%s", + VTY_NEWLINE); + return CMD_WARNING; + } - if (use_json) - { - json_scode = json_object_new_object(); - json_ocode = json_object_new_object(); - json = json_object_new_object(); - json_nroute = json_object_new_object(); + if (use_json) { + json_scode = json_object_new_object(); + json_ocode = json_object_new_object(); + json = json_object_new_object(); + json_nroute = json_object_new_object(); - json_object_string_add(json_scode, "suppressed", "s"); - json_object_string_add(json_scode, "damped", "d"); - json_object_string_add(json_scode, "history", "h"); - json_object_string_add(json_scode, "valid", "*"); - json_object_string_add(json_scode, "best", ">"); - json_object_string_add(json_scode, "internal", "i"); + json_object_string_add(json_scode, "suppressed", "s"); + json_object_string_add(json_scode, "damped", "d"); + json_object_string_add(json_scode, "history", "h"); + json_object_string_add(json_scode, "valid", "*"); + json_object_string_add(json_scode, "best", ">"); + json_object_string_add(json_scode, "internal", "i"); - json_object_string_add(json_ocode, "igp", "i"); - json_object_string_add(json_ocode, "egp", "e"); - json_object_string_add(json_ocode, "incomplete", "?"); - } + json_object_string_add(json_ocode, "igp", "i"); + json_object_string_add(json_ocode, "egp", "e"); + json_object_string_add(json_ocode, "incomplete", "?"); + } - for (rn = bgp_table_top (bgp->rib[afi][SAFI_EVPN]); rn; rn = bgp_route_next (rn)) - { - if (use_json) - continue; /* XXX json TODO */ + for (rn = bgp_table_top(bgp->rib[afi][SAFI_EVPN]); rn; + rn = bgp_route_next(rn)) { + if (use_json) + continue; /* XXX json TODO */ - if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) - continue; + if (prd && memcmp(rn->p.u.val, prd->val, 8) != 0) + continue; - if ((table = rn->info) != NULL) - { - rd_header = 1; + if ((table = rn->info) != NULL) { + rd_header = 1; - for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) - for (ri = rm->info; ri; ri = ri->next) - { - total_count++; - if (type == bgp_show_type_neighbor) - { - union sockunion *su = output_arg; + for (rm = bgp_table_top(table); rm; + rm = bgp_route_next(rm)) + for (ri = rm->info; ri; ri = ri->next) { + total_count++; + if (type == bgp_show_type_neighbor) { + union sockunion *su = + output_arg; - if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) - continue; - } - if (header == 0) - { - if (use_json) - { - if (option == SHOW_DISPLAY_TAGS) - { - json_object_int_add(json, "bgpTableVersion", 0); - json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id)); - json_object_object_add(json, "bgpStatusCodes", json_scode); - json_object_object_add(json, "bgpOriginCodes", json_ocode); - } - } - else - { - if (option == SHOW_DISPLAY_TAGS) - vty_out (vty, v4_header_tag, VTY_NEWLINE); - else if (option == SHOW_DISPLAY_OVERLAY) - vty_out (vty, v4_header_overlay, VTY_NEWLINE); - else - { - vty_out (vty, "BGP table version is 0, local router ID is %s%s", - inet_ntoa (bgp->router_id), VTY_NEWLINE); - vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", - VTY_NEWLINE); - vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", - VTY_NEWLINE, VTY_NEWLINE); - vty_out (vty, v4_header, VTY_NEWLINE); - } - } - header = 0; - } - if (rd_header) - { - u_int16_t type; - struct rd_as rd_as; - struct rd_ip rd_ip; - u_char *pnt; + if (ri->peer->su_remote == NULL + || !sockunion_same(ri-> + peer-> + su_remote, + su)) + continue; + } + if (header == 0) { + if (use_json) { + if (option == + SHOW_DISPLAY_TAGS) { + json_object_int_add + (json, + "bgpTableVersion", + 0); + json_object_string_add + (json, + "bgpLocalRouterId", + inet_ntoa + (bgp-> + router_id)); + json_object_object_add + (json, + "bgpStatusCodes", + json_scode); + json_object_object_add + (json, + "bgpOriginCodes", + json_ocode); + } + } else { + if (option == + SHOW_DISPLAY_TAGS) + vty_out(vty, + v4_header_tag, + VTY_NEWLINE); + else if (option == + SHOW_DISPLAY_OVERLAY) + vty_out(vty, + v4_header_overlay, + VTY_NEWLINE); + else { + vty_out(vty, + "BGP table version is 0, local router ID is %s%s", + inet_ntoa + (bgp-> + router_id), + VTY_NEWLINE); + vty_out(vty, + "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", + VTY_NEWLINE); + vty_out(vty, + "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", + VTY_NEWLINE, + VTY_NEWLINE); + vty_out(vty, + v4_header, + VTY_NEWLINE); + } + } + header = 0; + } + if (rd_header) { + u_int16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + u_char *pnt; - pnt = rn->p.u.val; + pnt = rn->p.u.val; - /* Decode RD type. */ - type = decode_rd_type (pnt); - /* Decode RD value. */ - if (type == RD_TYPE_AS) - decode_rd_as (pnt + 2, &rd_as); - else if (type == RD_TYPE_AS4) - decode_rd_as4 (pnt + 2, &rd_as); - else if (type == RD_TYPE_IP) - decode_rd_ip (pnt + 2, &rd_ip); - if (use_json) - { - char buffer[BUFSIZ]; - if (type == RD_TYPE_AS || type == RD_TYPE_AS4) - sprintf (buffer, "%u:%d", rd_as.as, rd_as.val); - else if (type == RD_TYPE_IP) - sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); - json_object_string_add(json_nroute, "routeDistinguisher", buffer); - } - else - { - vty_out (vty, "Route Distinguisher: "); - if (type == RD_TYPE_AS) - vty_out (vty, "as2 %u:%d", rd_as.as, rd_as.val); - else if (type == RD_TYPE_AS4) - vty_out (vty, "as4 %u:%d", rd_as.as, rd_as.val); - else if (type == RD_TYPE_IP) - vty_out (vty, "ip %s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); - vty_out (vty, "%s", VTY_NEWLINE); - } - rd_header = 0; - } - if (use_json) - json_array = json_object_new_array(); - else - json_array = NULL; - if (option == SHOW_DISPLAY_TAGS) - route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_EVPN, json_array); - else if (option == SHOW_DISPLAY_OVERLAY) - route_vty_out_overlay (vty, &rm->p, ri, 0, json_array); - else - route_vty_out (vty, &rm->p, ri, 0, SAFI_EVPN, json_array); - output_count++; - } - /* XXX json */ - } - } - if (output_count == 0) - vty_out (vty, "No prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE); - else - vty_out (vty, "%sDisplayed %ld out of %ld total prefixes%s", - VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); - return CMD_SUCCESS; + /* Decode RD type. */ + type = decode_rd_type(pnt); + /* Decode RD value. */ + if (type == RD_TYPE_AS) + decode_rd_as(pnt + 2, + &rd_as); + else if (type == RD_TYPE_AS4) + decode_rd_as4(pnt + 2, + &rd_as); + else if (type == RD_TYPE_IP) + decode_rd_ip(pnt + 2, + &rd_ip); + if (use_json) { + char buffer[BUFSIZ]; + if (type == RD_TYPE_AS + || type == + RD_TYPE_AS4) + sprintf(buffer, + "%u:%d", + rd_as. + as, + rd_as. + val); + else if (type == + RD_TYPE_IP) + sprintf(buffer, + "%s:%d", + inet_ntoa + (rd_ip. + ip), + rd_ip. + val); + json_object_string_add + (json_nroute, + "routeDistinguisher", + buffer); + } else { + vty_out(vty, + "Route Distinguisher: "); + if (type == RD_TYPE_AS) + vty_out(vty, + "as2 %u:%d", + rd_as. + as, + rd_as. + val); + else if (type == + RD_TYPE_AS4) + vty_out(vty, + "as4 %u:%d", + rd_as. + as, + rd_as. + val); + else if (type == + RD_TYPE_IP) + vty_out(vty, + "ip %s:%d", + inet_ntoa + (rd_ip. + ip), + rd_ip. + val); + vty_out(vty, "%s", + VTY_NEWLINE); + } + rd_header = 0; + } + if (use_json) + json_array = + json_object_new_array(); + else + json_array = NULL; + if (option == SHOW_DISPLAY_TAGS) + route_vty_out_tag(vty, &rm->p, + ri, 0, + SAFI_EVPN, + json_array); + else if (option == SHOW_DISPLAY_OVERLAY) + route_vty_out_overlay(vty, + &rm->p, + ri, 0, + json_array); + else + route_vty_out(vty, &rm->p, ri, + 0, SAFI_EVPN, + json_array); + output_count++; + } + /* XXX json */ + } + } + if (output_count == 0) + vty_out(vty, "No prefixes displayed, %ld exist%s", total_count, + VTY_NEWLINE); + else + vty_out(vty, "%sDisplayed %ld out of %ld total prefixes%s", + VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); + return CMD_SUCCESS; } -DEFUN (show_ip_bgp_l2vpn_evpn, - show_ip_bgp_l2vpn_evpn_cmd, - "show [ip] bgp l2vpn evpn [json]", - SHOW_STR - IP_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - JSON_STR) +DEFUN(show_ip_bgp_l2vpn_evpn, + show_ip_bgp_l2vpn_evpn_cmd, + "show [ip] bgp l2vpn evpn [json]", + SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR JSON_STR) { - return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, 0, use_json (argc, argv)); + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 0, + use_json(argc, argv)); } -DEFUN (show_ip_bgp_l2vpn_evpn_rd, - show_ip_bgp_l2vpn_evpn_rd_cmd, - "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn [json]", - SHOW_STR - IP_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" - JSON_STR) +DEFUN(show_ip_bgp_l2vpn_evpn_rd, + show_ip_bgp_l2vpn_evpn_rd_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" JSON_STR) { - int idx_ext_community = 6; - int ret; - struct prefix_rd prd; + int idx_ext_community = 6; + int ret; + struct prefix_rd prd; - ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); - if (! ret) - { - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_normal, NULL, 0, use_json (argc, argv)); + ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); + if (!ret) { + vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 0, + use_json(argc, argv)); } -DEFUN (show_ip_bgp_l2vpn_evpn_all_tags, - show_ip_bgp_l2vpn_evpn_all_tags_cmd, - "show [ip] bgp l2vpn evpn all tags", - SHOW_STR - IP_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Display information about all EVPN NLRIs\n" - "Display BGP tags for prefixes\n") +DEFUN(show_ip_bgp_l2vpn_evpn_all_tags, + show_ip_bgp_l2vpn_evpn_all_tags_cmd, + "show [ip] bgp l2vpn evpn all tags", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Display BGP tags for prefixes\n") { - return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, 1, 0); + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 1, + 0); } -DEFUN (show_ip_bgp_l2vpn_evpn_rd_tags, - show_ip_bgp_l2vpn_evpn_rd_tags_cmd, - "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn tags", - SHOW_STR - IP_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" - "Display BGP tags for prefixes\n") +DEFUN(show_ip_bgp_l2vpn_evpn_rd_tags, + show_ip_bgp_l2vpn_evpn_rd_tags_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn tags", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n") { - int idx_ext_community = 6; - int ret; - struct prefix_rd prd; + int idx_ext_community = 6; + int ret; + struct prefix_rd prd; - ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); - if (! ret) - { - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_ethernet_vpn (vty,&prd, bgp_show_type_normal, NULL, 1, 0); + ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); + if (!ret) { + vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 1, + 0); } -DEFUN (show_ip_bgp_l2vpn_evpn_all_neighbor_routes, - show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd, - "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]", - SHOW_STR - IP_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Display information about all EVPN NLRIs\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Display routes learned from neighbor\n" - JSON_STR) +DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_routes, + show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd, + "show [ip] bgp l2vpn evpn all neighbors A.B.C.D routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n" JSON_STR) { - int idx_ipv4 = 6; - union sockunion su; - struct peer *peer; - int ret; - u_char uj = use_json(argc, argv); + int idx_ipv4 = 6; + union sockunion su; + struct peer *peer; + int ret; + u_char uj = use_json(argc, argv); - ret = str2sockunion (argv[idx_ipv4]->arg, &su); - if (ret < 0) - { - if (uj) - { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", "Malformed address"); - vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); - json_object_free(json_no); - } - else - vty_out (vty, "Malformed address: %s%s", argv[idx_ipv4]->arg, VTY_NEWLINE); - return CMD_WARNING; - } + ret = str2sockunion(argv[idx_ipv4]->arg, &su); + if (ret < 0) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "Malformed address"); + vty_out(vty, "%s%s", + json_object_to_json_string(json_no), + VTY_NEWLINE); + json_object_free(json_no); + } else + vty_out(vty, "Malformed address: %s%s", + argv[idx_ipv4]->arg, VTY_NEWLINE); + return CMD_WARNING; + } - peer = peer_lookup (NULL, &su); - if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) - { - if (uj) - { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", "No such neighbor or address family"); - vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); - json_object_free(json_no); - } - else - vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); - return CMD_WARNING; - } + peer = peer_lookup(NULL, &su); + if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "No such neighbor or address family"); + vty_out(vty, "%s%s", + json_object_to_json_string(json_no), + VTY_NEWLINE); + json_object_free(json_no); + } else + vty_out(vty, "%% No such neighbor or address family%s", + VTY_NEWLINE); + return CMD_WARNING; + } - return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_neighbor, &su, 0, uj); + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, &su, 0, + uj); } -DEFUN (show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, - show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd, - "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes [json]", - SHOW_STR - IP_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Display routes learned from neighbor\n" - JSON_STR) +DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, + show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display routes learned from neighbor\n" JSON_STR) { - int idx_ext_community = 6; - int idx_ipv4 = 8; - int ret; - union sockunion su; - struct peer *peer; - struct prefix_rd prd; - u_char uj = use_json(argc, argv); + int idx_ext_community = 6; + int idx_ipv4 = 8; + int ret; + union sockunion su; + struct peer *peer; + struct prefix_rd prd; + u_char uj = use_json(argc, argv); - ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); - if (! ret) - { - if (uj) - { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", "Malformed Route Distinguisher"); - vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); - json_object_free(json_no); - } - else - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); - return CMD_WARNING; - } + ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); + if (!ret) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "Malformed Route Distinguisher"); + vty_out(vty, "%s%s", + json_object_to_json_string(json_no), + VTY_NEWLINE); + json_object_free(json_no); + } else + vty_out(vty, "%% Malformed Route Distinguisher%s", + VTY_NEWLINE); + return CMD_WARNING; + } - ret = str2sockunion (argv[idx_ipv4]->arg, &su); - if (ret < 0) - { - if (uj) - { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", "Malformed address"); - vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); - json_object_free(json_no); - } - else - vty_out (vty, "Malformed address: %s%s", argv[idx_ext_community]->arg, VTY_NEWLINE); - return CMD_WARNING; - } + ret = str2sockunion(argv[idx_ipv4]->arg, &su); + if (ret < 0) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "Malformed address"); + vty_out(vty, "%s%s", + json_object_to_json_string(json_no), + VTY_NEWLINE); + json_object_free(json_no); + } else + vty_out(vty, "Malformed address: %s%s", + argv[idx_ext_community]->arg, VTY_NEWLINE); + return CMD_WARNING; + } - peer = peer_lookup (NULL, &su); - if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) - { - if (uj) - { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", "No such neighbor or address family"); - vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); - json_object_free(json_no); - } - else - vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); - return CMD_WARNING; - } + peer = peer_lookup(NULL, &su); + if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "No such neighbor or address family"); + vty_out(vty, "%s%s", + json_object_to_json_string(json_no), + VTY_NEWLINE); + json_object_free(json_no); + } else + vty_out(vty, "%% No such neighbor or address family%s", + VTY_NEWLINE); + return CMD_WARNING; + } - return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_neighbor, &su, 0, uj); + return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, &su, 0, + uj); } -DEFUN (show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes, - show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd, - "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]", - SHOW_STR - IP_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Display information about all EVPN NLRIs\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Display the routes advertised to a BGP neighbor\n" - JSON_STR) +DEFUN(show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes, + show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd, + "show [ip] bgp l2vpn evpn all neighbors A.B.C.D advertised-routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n" JSON_STR) { - int idx_ipv4 = 7; - int ret; - struct peer *peer; - union sockunion su; - u_char uj = use_json(argc, argv); + int idx_ipv4 = 7; + int ret; + struct peer *peer; + union sockunion su; + u_char uj = use_json(argc, argv); - ret = str2sockunion (argv[idx_ipv4]->arg, &su); - if (ret < 0) - { - if (uj) - { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", "Malformed address"); - vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); - json_object_free(json_no); - } - else - vty_out (vty, "Malformed address: %s%s", argv[idx_ipv4]->arg, VTY_NEWLINE); - return CMD_WARNING; - } - peer = peer_lookup (NULL, &su); - if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) - { - if (uj) - { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", "No such neighbor or address family"); - vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); - json_object_free(json_no); - } - else - vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); - return CMD_WARNING; - } + ret = str2sockunion(argv[idx_ipv4]->arg, &su); + if (ret < 0) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "Malformed address"); + vty_out(vty, "%s%s", + json_object_to_json_string(json_no), + VTY_NEWLINE); + json_object_free(json_no); + } else + vty_out(vty, "Malformed address: %s%s", + argv[idx_ipv4]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup(NULL, &su); + if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "No such neighbor or address family"); + vty_out(vty, "%s%s", + json_object_to_json_string(json_no), + VTY_NEWLINE); + json_object_free(json_no); + } else + vty_out(vty, "%% No such neighbor or address family%s", + VTY_NEWLINE); + return CMD_WARNING; + } - return show_adj_route_vpn (vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, uj); + return show_adj_route_vpn(vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, uj); } -DEFUN (show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, - show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd, - "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes [json]", - SHOW_STR - IP_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" - "Detailed information on TCP and BGP neighbor connections\n" - "Neighbor to display information about\n" - "Display the routes advertised to a BGP neighbor\n" - JSON_STR) +DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, + show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes [json]", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Detailed information on TCP and BGP neighbor connections\n" + "Neighbor to display information about\n" + "Display the routes advertised to a BGP neighbor\n" JSON_STR) { - int idx_ext_community = 6; - int idx_ipv4 = 8; - int ret; - struct peer *peer; - struct prefix_rd prd; - union sockunion su; - u_char uj = use_json(argc, argv); + int idx_ext_community = 6; + int idx_ipv4 = 8; + int ret; + struct peer *peer; + struct prefix_rd prd; + union sockunion su; + u_char uj = use_json(argc, argv); - ret = str2sockunion (argv[idx_ipv4]->arg, &su); - if (ret < 0) - { - if (uj) - { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", "Malformed address"); - vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); - json_object_free(json_no); - } - else - vty_out (vty, "Malformed address: %s%s", argv[idx_ext_community]->arg, VTY_NEWLINE); - return CMD_WARNING; - } - peer = peer_lookup (NULL, &su); - if (! peer || ! peer->afc[AFI_L2VPN][SAFI_EVPN]) - { - if (uj) - { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", "No such neighbor or address family"); - vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); - json_object_free(json_no); - } - else - vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); - return CMD_WARNING; - } + ret = str2sockunion(argv[idx_ipv4]->arg, &su); + if (ret < 0) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "Malformed address"); + vty_out(vty, "%s%s", + json_object_to_json_string(json_no), + VTY_NEWLINE); + json_object_free(json_no); + } else + vty_out(vty, "Malformed address: %s%s", + argv[idx_ext_community]->arg, VTY_NEWLINE); + return CMD_WARNING; + } + peer = peer_lookup(NULL, &su); + if (!peer || !peer->afc[AFI_L2VPN][SAFI_EVPN]) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "No such neighbor or address family"); + vty_out(vty, "%s%s", + json_object_to_json_string(json_no), + VTY_NEWLINE); + json_object_free(json_no); + } else + vty_out(vty, "%% No such neighbor or address family%s", + VTY_NEWLINE); + return CMD_WARNING; + } - ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); - if (! ret) - { - if (uj) - { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", "Malformed Route Distinguisher"); - vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); - json_object_free(json_no); - } - else - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); - return CMD_WARNING; - } + ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); + if (!ret) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add(json_no, "warning", + "Malformed Route Distinguisher"); + vty_out(vty, "%s%s", + json_object_to_json_string(json_no), + VTY_NEWLINE); + json_object_free(json_no); + } else + vty_out(vty, "%% Malformed Route Distinguisher%s", + VTY_NEWLINE); + return CMD_WARNING; + } - return show_adj_route_vpn (vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj); + return show_adj_route_vpn(vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj); } -DEFUN (show_ip_bgp_l2vpn_evpn_all_overlay, - show_ip_bgp_l2vpn_evpn_all_overlay_cmd, - "show [ip] bgp l2vpn evpn all overlay", - SHOW_STR - IP_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Display information about all EVPN NLRIs\n" - "Display BGP Overlay Information for prefixes\n") +DEFUN(show_ip_bgp_l2vpn_evpn_all_overlay, + show_ip_bgp_l2vpn_evpn_all_overlay_cmd, + "show [ip] bgp l2vpn evpn all overlay", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information about all EVPN NLRIs\n" + "Display BGP Overlay Information for prefixes\n") { - return bgp_show_ethernet_vpn (vty, NULL, bgp_show_type_normal, NULL, - SHOW_DISPLAY_OVERLAY, use_json (argc, argv)); + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, + SHOW_DISPLAY_OVERLAY, use_json(argc, + argv)); } -DEFUN (show_ip_bgp_evpn_rd_overlay, - show_ip_bgp_evpn_rd_overlay_cmd, - "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn overlay", - SHOW_STR - IP_STR - BGP_STR - L2VPN_HELP_STR - EVPN_HELP_STR - "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" - "Display BGP Overlay Information for prefixes\n") +DEFUN(show_ip_bgp_evpn_rd_overlay, + show_ip_bgp_evpn_rd_overlay_cmd, + "show [ip] bgp l2vpn evpn rd ASN:nn_or_IP-address:nn overlay", + SHOW_STR + IP_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Display information for a route distinguisher\n" + "VPN Route Distinguisher\n" + "Display BGP Overlay Information for prefixes\n") { - int idx_ext_community = 6; - int ret; - struct prefix_rd prd; + int idx_ext_community = 6; + int ret; + struct prefix_rd prd; - ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); - if (! ret) - { - vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); - return CMD_WARNING; - } - return bgp_show_ethernet_vpn (vty, &prd, bgp_show_type_normal, NULL, - SHOW_DISPLAY_OVERLAY, use_json (argc, argv)); + ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); + if (!ret) { + vty_out(vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); + return CMD_WARNING; + } + return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, + SHOW_DISPLAY_OVERLAY, use_json(argc, + argv)); } /* For testing purpose, static route of MPLS-VPN. */ -DEFUN (evpnrt5_network, - evpnrt5_network_cmd, - "network rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip routermac WORD [route-map WORD]", - "Specify a network to announce via BGP\n" - "IP prefix\n" - "IPv6 prefix\n" - "Specify Route Distinguisher\n" - "VPN Route Distinguisher\n" - "Ethernet Tag\n" - "Ethernet Tag Value\n" - "BGP label\n" - "label value\n" - "Ethernet Segment Identifier\n" - "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n" - "Gateway IP\n" - "Gateway IP ( A.B.C.D )\n" - "Gateway IPv6 ( X:X::X:X )\n" - "Router Mac Ext Comm\n" - "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n") +DEFUN(evpnrt5_network, + evpnrt5_network_cmd, + "network rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip routermac WORD [route-map WORD]", + "Specify a network to announce via BGP\n" + "IP prefix\n" + "IPv6 prefix\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "Ethernet Tag\n" + "Ethernet Tag Value\n" + "BGP label\n" + "label value\n" + "Ethernet Segment Identifier\n" + "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n" + "Gateway IP\n" + "Gateway IP ( A.B.C.D )\n" + "Gateway IPv6 ( X:X::X:X )\n" + "Router Mac Ext Comm\n" + "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n") { - int idx_ipv4_prefixlen = 1; - int idx_ext_community = 3; - int idx_word = 7; - int idx_esi = 9; - int idx_gwip = 11; - int idx_ethtag = 5; - int idx_routermac = 13; - int idx_rmap = 15; - return bgp_static_set_safi (SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, - argv[idx_word]->arg, argv[idx_rmap]?argv[idx_gwip]->arg:NULL, - EVPN_IP_PREFIX, argv[idx_esi]->arg, argv[idx_gwip]->arg, - argv[idx_ethtag]->arg, argv[idx_routermac]->arg); + int idx_ipv4_prefixlen = 1; + int idx_ext_community = 3; + int idx_word = 7; + int idx_esi = 9; + int idx_gwip = 11; + int idx_ethtag = 5; + int idx_routermac = 13; + int idx_rmap = 15; + return bgp_static_set_safi(SAFI_EVPN, vty, + argv[idx_ipv4_prefixlen]->arg, + argv[idx_ext_community]->arg, + argv[idx_word]->arg, + argv[idx_rmap] ? argv[idx_gwip]->arg : NULL, + EVPN_IP_PREFIX, argv[idx_esi]->arg, + argv[idx_gwip]->arg, argv[idx_ethtag]->arg, + argv[idx_routermac]->arg); } /* For testing purpose, static route of MPLS-VPN. */ -DEFUN (no_evpnrt5_network, - no_evpnrt5_network_cmd, - "no network rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip ", - NO_STR - "Specify a network to announce via BGP\n" - "IP prefix\n" - "IPv6 prefix\n" - "Specify Route Distinguisher\n" - "VPN Route Distinguisher\n" - "Ethernet Tag\n" - "Ethernet Tag Value\n" - "BGP label\n" - "label value\n" - "Ethernet Segment Identifier\n" - "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n" - "Gateway IP\n" - "Gateway IP ( A.B.C.D )\n" - "Gateway IPv6 ( X:X::X:X )\n") +DEFUN(no_evpnrt5_network, + no_evpnrt5_network_cmd, + "no network rd ASN:nn_or_IP-address:nn ethtag WORD label WORD esi WORD gwip ", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix\n" + "IPv6 prefix\n" + "Specify Route Distinguisher\n" + "VPN Route Distinguisher\n" + "Ethernet Tag\n" + "Ethernet Tag Value\n" + "BGP label\n" + "label value\n" + "Ethernet Segment Identifier\n" + "ESI value ( 00:11:22:33:44:55:66:77:88:99 format) \n" + "Gateway IP\n" "Gateway IP ( A.B.C.D )\n" "Gateway IPv6 ( X:X::X:X )\n") { - int idx_ipv4_prefixlen = 2; - int idx_ext_community = 4; - int idx_label = 8; - int idx_ethtag = 6; - int idx_esi = 10; - int idx_gwip = 12; - return bgp_static_unset_safi (SAFI_EVPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_label]->arg, - EVPN_IP_PREFIX, argv[idx_esi]->arg, argv[idx_gwip]->arg, argv[idx_ethtag]->arg); + int idx_ipv4_prefixlen = 2; + int idx_ext_community = 4; + int idx_label = 8; + int idx_ethtag = 6; + int idx_esi = 10; + int idx_gwip = 12; + return bgp_static_unset_safi(SAFI_EVPN, vty, + argv[idx_ipv4_prefixlen]->arg, + argv[idx_ext_community]->arg, + argv[idx_label]->arg, EVPN_IP_PREFIX, + argv[idx_esi]->arg, argv[idx_gwip]->arg, + argv[idx_ethtag]->arg); } - -void -bgp_ethernetvpn_init (void) +void bgp_ethernetvpn_init(void) { - install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd); - install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd); - install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd); - install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd); - install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd); - install_element (VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd); - install_element (VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd); - install_element (BGP_EVPN_NODE, &no_evpnrt5_network_cmd); - install_element (BGP_EVPN_NODE, &evpnrt5_network_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_tags_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_rd_tags_cmd); + install_element(VIEW_NODE, + &show_ip_bgp_l2vpn_evpn_all_neighbor_routes_cmd); + install_element(VIEW_NODE, + &show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd); + install_element(VIEW_NODE, + &show_ip_bgp_l2vpn_evpn_all_neighbor_advertised_routes_cmd); + install_element(VIEW_NODE, + &show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd); + install_element(VIEW_NODE, &show_ip_bgp_evpn_rd_overlay_cmd); + install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_all_overlay_cmd); + install_element(BGP_EVPN_NODE, &no_evpnrt5_network_cmd); + install_element(BGP_EVPN_NODE, &evpnrt5_network_cmd); } diff --git a/bgpd/bgp_evpn_vty.h b/bgpd/bgp_evpn_vty.h index ed654d90b2..11e93a5281 100644 --- a/bgpd/bgp_evpn_vty.h +++ b/bgpd/bgp_evpn_vty.h @@ -21,11 +21,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #ifndef _FRR_BGP_EVPN_VTY_H #define _FRR_BGP_EVPN_VTY_H -extern void -bgp_ethernetvpn_init (void); +extern void bgp_ethernetvpn_init(void); #define L2VPN_HELP_STR "Layer 2 Virtual Private Network\n" #define EVPN_HELP_STR "Ethernet Virtual Private Network\n" - -#endif /* _QUAGGA_BGP_EVPN_VTY_H */ +#endif /* _QUAGGA_BGP_EVPN_VTY_H */ From 72831436ed8ffa1c826c64a67e63ba3fe85d6d7f Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 30 Jan 2017 14:57:55 +0100 Subject: [PATCH 42/64] bgpd: fix rfapi call to ecom2str with correct number of parameters This commit is a complement for bgpd: handling router mac extended community. As API of bgp_ecommunity ecom2str() function changed, rfapi file has diverged with this API. The commit adds the correct number of parameters. Signed-off-by: Philippe Guibert --- bgpd/rfapi/bgp_rfapi_cfg.c | 8 +++++--- bgpd/rfapi/rfapi.c | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index 2739b1ff10..71086c8758 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -4685,7 +4685,8 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp) ecommunity_cmp (rfg->rt_import_list, rfg->rt_export_list)) { char *b = ecommunity_ecom2str (rfg->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt both %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } @@ -4694,14 +4695,15 @@ bgp_rfapi_cfg_write (struct vty *vty, struct bgp *bgp) if (rfg->rt_import_list) { char *b = ecommunity_ecom2str (rfg->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, + ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt import %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } if (rfg->rt_export_list) { char *b = ecommunity_ecom2str (rfg->rt_export_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vty_out (vty, " rt export %s%s", b, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, b); } diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 56ca25a131..351d4b6d5a 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -1733,7 +1733,7 @@ rfapi_query_inner ( __func__, rfd, buf, ppNextHopEntry); s = ecommunity_ecom2str(rfd->import_table->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP); + ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); vnc_zlog_debug_verbose("%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s", __func__, rfd->import_table, s); XFREE (MTYPE_ECOMMUNITY_STR, s); } From c215ecaf837f770f401b949a021c9e0f09421a37 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 1 Feb 2017 18:26:34 +0100 Subject: [PATCH 43/64] lib: add string to macaddress and reverse function As mac-address structure is to be used as a prefix field, two new functions permit handling mac address in order to convert it. either from string to internal value, or the reverse operation. Internal representation of a mac address is a 6 byte char value standing for the 6 byte value the mac address has. Signed-off-by: Philippe Guibert --- lib/prefix.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/prefix.h | 8 ++++ 2 files changed, 123 insertions(+) diff --git a/lib/prefix.c b/lib/prefix.c index 1b168abedc..75879b5c51 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1023,3 +1023,118 @@ inet6_ntoa (struct in6_addr addr) inet_ntop (AF_INET6, &addr, buf, INET6_ADDRSTRLEN); return buf; } + + +static uint8_t convertchartohexa(uint8_t * hexa, int *error) +{ + if ((*hexa == '0') || (*hexa == '1') || (*hexa == '2') || + (*hexa == '3') || (*hexa == '4') || (*hexa == '5') || + (*hexa == '6') || (*hexa == '7') || (*hexa == '8') + || (*hexa == '9')) + return (uint8_t) (*hexa) - '0'; + if ((*hexa == 'a') || (*hexa == 'A')) + return 0xa; + if ((*hexa == 'b') || (*hexa == 'B')) + return 0xb; + if ((*hexa == 'c') || (*hexa == 'C')) + return 0xc; + if ((*hexa == 'd') || (*hexa == 'D')) + return 0xd; + if ((*hexa == 'e') || (*hexa == 'E')) + return 0xe; + if ((*hexa == 'f') || (*hexa == 'F')) + return 0xf; + *error = -1; + return 0; +} + +/* 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 + */ +int str2mac(const char *str, char *mac) +{ + unsigned int k = 0, i, j; + uint8_t *ptr, *ptr2; + size_t len; + uint8_t car; + + if (!str) + return 0; + + if (str[0] == ':' && str[1] == '\0') + return 1; + + i = 0; + ptr = (uint8_t *) str; + while (i < 6) { + uint8_t temp[5]; + int error = 0; + ptr2 = (uint8_t *) strchr((const char *)ptr, ':'); + if (ptr2 == NULL) { + /* if last occurence return ok */ + if (i != 5) { + zlog_err("[%s]: format non recognized", mac); + return 0; + } + len = strlen((char *)ptr); + } else { + len = ptr2 - ptr; + } + if (len > 5) { + zlog_err("[%s]: format non recognized", mac); + return 0; + } + memcpy(temp, ptr, len); + for (j = 0; j < len; j++) { + if (k >= ETHER_ADDR_LEN) + return 0; + if (mac) + mac[k] = 0; + car = convertchartohexa(&temp[j], &error); + if (error) + return 0; + if (mac) + mac[k] = car << 4; + j++; + if (j == len) + return 0; + car = convertchartohexa(&temp[j], &error) & 0xf; + if (error) + return 0; + if (mac) + mac[k] |= car & 0xf; + k++; + i++; + } + ptr = ptr2; + if (ptr == NULL) + break; + ptr++; + } + if (mac && 0) { + zlog_err("leave correct : %02x:%02x:%02x:%02x:%02x:%02x", + mac[0] & 0xff, mac[1] & 0xff, mac[2] & 0xff, + mac[3] & 0xff, mac[4] & 0xff, mac[5] & 0xff); + } + return 1; +} + +char *mac2str(char *mac, char *buf, int size) +{ + char *ptr; + + assert (size > ETHER_ADDR_STRLEN); + if (!mac) + return NULL; + if (!buf) + ptr = (char *)XMALLOC(MTYPE_TMP, ETHER_ADDR_STRLEN* sizeof(char)); + else + ptr = buf; + snprintf(ptr, (ETHER_ADDR_STRLEN), + "%02x:%02x:%02x:%02x:%02x:%02x", (uint8_t) mac[0], + (uint8_t) mac[1], (uint8_t) mac[2], (uint8_t) mac[3], + (uint8_t) mac[4], (uint8_t) mac[5]); + return ptr; +} diff --git a/lib/prefix.h b/lib/prefix.h index 472dc1a01a..53cf9208e5 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -35,9 +35,14 @@ #include "sockunion.h" #ifndef ETHER_ADDR_LEN +#ifdef ETHERADDRL #define ETHER_ADDR_LEN ETHERADDRL +#else +#define ETHER_ADDR_LEN 6 +#endif #endif +#define ETHER_ADDR_STRLEN (3*ETHER_ADDR_LEN) /* * there isn't a portable ethernet address type. We define our * own to simplify internal handling @@ -322,6 +327,9 @@ extern void masklen2ip6 (const int, struct in6_addr *); extern const char *inet6_ntoa (struct in6_addr); +extern int str2mac(const char *str, char *mac); +extern char *mac2str(char *mac, char *buf, int size); + static inline int ipv6_martian (struct in6_addr *addr) { struct in6_addr localhost_addr; From 0362b0a7ec8bdd58cea755d97972c2f2ae4a9bbf Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 1 Feb 2017 19:05:19 +0100 Subject: [PATCH 44/64] lib: handle str2mac case where buffer is allocated by the function The case where no buffer is passed to the str2mac function is handled. In that case, a buffer is allocated. Then the check against the buffer length is not done. Signed-off-by: Philippe Guibert --- lib/prefix.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index 75879b5c51..bef28ff9ec 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1125,13 +1125,15 @@ char *mac2str(char *mac, char *buf, int size) { char *ptr; - assert (size > ETHER_ADDR_STRLEN); if (!mac) return NULL; if (!buf) ptr = (char *)XMALLOC(MTYPE_TMP, ETHER_ADDR_STRLEN* sizeof(char)); else - ptr = buf; + { + assert (size >= ETHER_ADDR_STRLEN); + ptr = buf; + } snprintf(ptr, (ETHER_ADDR_STRLEN), "%02x:%02x:%02x:%02x:%02x:%02x", (uint8_t) mac[0], (uint8_t) mac[1], (uint8_t) mac[2], (uint8_t) mac[3], From b2bc8e2331ad67f282d423c17204a27f6b69525a Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 1 Feb 2017 18:41:38 +0100 Subject: [PATCH 45/64] bgpd: use mac2str() function utility to display mac address VNC uses the prefix API to handle mac string. Signed-off-by: Philippe Guibert --- bgpd/rfapi/rfapi_vty.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index dbc2a430bc..997f1d3c34 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -314,19 +314,7 @@ rfapiL2o2Qprefix (struct rfapi_l2address_option *l2o, struct prefix *pfx) char * rfapiEthAddr2Str (const struct ethaddr *ea, char *buf, int bufsize) { - int i; - char *p = buf; - - assert (bufsize > (3 * ETHER_ADDR_LEN)); - - for (i = 0; i <= ETHER_ADDR_LEN; ++i) - { - sprintf (p, "%02x", ea->octet[i]); - if (i < (ETHER_ADDR_LEN - 1)) - *(p + 2) = ':'; - p += 3; - } - return buf; + return mac2str (ea->octet, buf, bufsize); } int From 0bee00f91573644b0f3ddc90a903762d1b731425 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 1 Feb 2017 18:52:33 +0100 Subject: [PATCH 46/64] bgpd: evpn use string handling functions from mac manipulation EVPN code adaptation to replace old mac string internal utility with the new one available in lib folder. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr_evpn.c | 94 +------------------------------------------- bgpd/bgp_attr_evpn.h | 3 -- bgpd/bgp_route.c | 8 ++-- 3 files changed, 7 insertions(+), 98 deletions(-) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 31f75baa20..5969df211f 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -42,7 +42,7 @@ void bgp_add_routermac_ecom(struct attr *attr, char *routermac) memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; - memcpy(&routermac_ecom.val[2], routermac, MAC_LEN); + memcpy(&routermac_ecom.val[2], routermac, ETHER_ADDR_LEN); if (!attr->extra->ecommunity) attr->extra->ecommunity = ecommunity_new(); ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom); @@ -72,79 +72,6 @@ static uint8_t convertchartohexa(uint8_t * hexa, int *error) return 0; } -/* 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 - */ -int str2mac(const char *str, char *mac) -{ - unsigned int k = 0, i, j; - uint8_t *ptr, *ptr2; - size_t len; - uint8_t car; - - if (!str) - return 0; - - if (str[0] == ':' && str[1] == '\0') - return 1; - - i = 0; - ptr = (uint8_t *) str; - while (i < 6) { - uint8_t temp[5]; - int error = 0; - ptr2 = (uint8_t *) strchr((const char *)ptr, ':'); - if (ptr2 == NULL) { - /* if last occurence return ok */ - if (i != 5) { - zlog_err("[%s]: format non recognized", mac); - return 0; - } - len = strlen((char *)ptr); - } else { - len = ptr2 - ptr; - } - if (len > 5) { - zlog_err("[%s]: format non recognized", mac); - return 0; - } - memcpy(temp, ptr, len); - for (j = 0; j < len; j++) { - if (k >= MAC_LEN) - return 0; - if (mac) - mac[k] = 0; - car = convertchartohexa(&temp[j], &error); - if (error) - return 0; - if (mac) - mac[k] = car << 4; - j++; - if (j == len) - return 0; - car = convertchartohexa(&temp[j], &error) & 0xf; - if (error) - return 0; - if (mac) - mac[k] |= car & 0xf; - k++; - i++; - } - ptr = ptr2; - if (ptr == NULL) - break; - ptr++; - } - if (mac && 0) { - zlog_err("leave correct : %02x:%02x:%02x:%02x:%02x:%02x", - mac[0] & 0xff, mac[1] & 0xff, mac[2] & 0xff, - mac[3] & 0xff, mac[4] & 0xff, mac[5] & 0xff); - } - return 1; -} - /* converts to an esi * returns 1 on success, 0 otherwise * format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ @@ -238,30 +165,13 @@ char *esi2str(struct eth_segment_id *id) return ptr; } -char *mac2str(char *mac) -{ - char *ptr; - - if (!mac) - return NULL; - - ptr = (char *)malloc((MAC_LEN * 2 + MAC_LEN - 1 + 1) * sizeof(char)); - - snprintf(ptr, (MAC_LEN * 2 + MAC_LEN - 1 + 1), - "%02x:%02x:%02x:%02x:%02x:%02x", (uint8_t) mac[0], - (uint8_t) mac[1], (uint8_t) mac[2], (uint8_t) mac[3], - (uint8_t) mac[4], (uint8_t) mac[5]); - - return ptr; -} - char *ecom_mac2str(char *ecom_mac) { char *en; en = ecom_mac; en += 2; - return mac2str(en); + return mac2str(en, NULL, 0); } /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */ diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index aff0ae4141..7fa7256ca0 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -39,8 +39,6 @@ struct eth_segment_id { u_char val[ESI_LEN]; }; -#define MAC_LEN 6 - union gw_addr { struct in_addr ipv4; struct in6_addr ipv6; @@ -54,7 +52,6 @@ struct bgp_route_evpn { extern int str2esi(const char *str, struct eth_segment_id *id); extern int str2mac(const char *str, char *mac); extern char *esi2str(struct eth_segment_id *id); -extern char *mac2str(char *mac); extern char *ecom_mac2str(char *ecom_mac); extern void bgp_add_routermac_ecom(struct attr *attr, char *routermac); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 085763ba81..dd0abb675c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4567,7 +4567,7 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, } if( routermac) { - bgp_static->router_mac = XCALLOC (MTYPE_ATTR, MAC_LEN+1); + bgp_static->router_mac = XCALLOC (MTYPE_ATTR, ETHER_ADDR_LEN+1); str2mac (routermac, bgp_static->router_mac); } if (gwip) @@ -6633,7 +6633,7 @@ route_vty_out_overlay (struct vty *vty, struct prefix *p, if(mac) { vty_out (vty, "/%s",(char *)mac); - free(mac); + XFREE(MTYPE_TMP, mac); } } } @@ -10531,7 +10531,7 @@ bgp_config_write_network_evpn (struct vty *vty, struct bgp *bgp, char *esi = NULL; if(bgp_static->router_mac) - macrouter = mac2str(bgp_static->router_mac); + macrouter = mac2str(bgp_static->router_mac, NULL, 0); if(bgp_static->eth_s_id) esi = esi2str(bgp_static->eth_s_id); p = &rn->p; @@ -10550,6 +10550,8 @@ bgp_config_write_network_evpn (struct vty *vty, struct bgp *bgp, buf, rdbuf, p->u.prefix_evpn.eth_tag, decode_label (bgp_static->tag), esi, buf2 , macrouter); vty_out (vty, "%s", VTY_NEWLINE); + if (macrouter) + XFREE (MTYPE_TMP, macrouter); } return 0; } From ffd28f0ec7818af78a550c853eb39763f8ab7438 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 1 Feb 2017 19:01:16 +0100 Subject: [PATCH 47/64] bgpd: use XMALLOC for ESI handling The memory allocation mecanism from frr is used. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr_evpn.c | 2 +- bgpd/bgp_route.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 5969df211f..929b4c17c3 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -155,7 +155,7 @@ char *esi2str(struct eth_segment_id *id) return NULL; val = id->val; - ptr = (char *)malloc((ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char)); + ptr = (char *)XMALLOC(MTYPE_TMP, (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char)); snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index dd0abb675c..3d23fa4ca6 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6611,7 +6611,7 @@ route_vty_out_overlay (struct vty *vty, struct prefix *p, struct eth_segment_id *id = &(attr->extra->evpn_overlay.eth_s_id); char *str = esi2str(id); vty_out (vty, "%s", str); - free(str); + XFREE (MTYPE_TMP, str); if (p->u.prefix_evpn.flags & IP_PREFIX_V4) { vty_out (vty, "/%s", inet_ntoa (attr->extra->evpn_overlay.gw_ip.ipv4)); @@ -10552,6 +10552,8 @@ bgp_config_write_network_evpn (struct vty *vty, struct bgp *bgp, vty_out (vty, "%s", VTY_NEWLINE); if (macrouter) XFREE (MTYPE_TMP, macrouter); + if (esi) + XFREE (MTYPE_TMP, esi); } return 0; } From 42f621a6ea35ed7021146710cc4c8c1b482df7b5 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 3 Feb 2017 07:59:20 +0100 Subject: [PATCH 48/64] lib: replace AFI_ETHER reference with AFI_L2VPN The introduction of AFI_L2VPN prefix makes usage of AFI_ETHER deprecated and is of no usage currently. The latter define is linked to AFI_L2VPN. For that, the prefix enumerate has the AFI_ETHER value removed. Signed-off-by: Philippe Guibert --- lib/plist.c | 2 +- lib/prefix.c | 2 -- lib/zebra.h | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/plist.c b/lib/plist.c index 4539d82972..9a2fc4af09 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -972,7 +972,7 @@ vty_prefix_list_install (struct vty *vty, afi_t afi, const char *name, apply_mask_ipv6 ((struct prefix_ipv6 *) &p_tmp); break; - case AFI_ETHER: + case AFI_L2VPN: default: vty_out (vty, "%% Unrecognized AFI (%d)%s", afi, VTY_NEWLINE); return CMD_WARNING; diff --git a/lib/prefix.c b/lib/prefix.c index bef28ff9ec..73af29ead3 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -234,8 +234,6 @@ afi2str(afi_t afi) return "IPv4"; case AFI_IP6: return "IPv6"; - case AFI_ETHER: - return "ethernet"; case AFI_L2VPN: return "l2vpn"; case AFI_MAX: diff --git a/lib/zebra.h b/lib/zebra.h index db6fcf93ad..760264d752 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -401,7 +401,6 @@ extern const char *zserv_command_string (unsigned int command); typedef enum { AFI_IP = 1, AFI_IP6 = 2, - AFI_ETHER = 3, /* RFC 1700 has "6" for 802.* */ AFI_L2VPN = 4, AFI_MAX = 5 } afi_t; From 5ef6cd6954fdd39ce4462987c2b9939d875a2ad7 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 3 Feb 2017 08:00:58 +0100 Subject: [PATCH 49/64] bgpd: replace AFI_ETHER reference with AFI_L2VPN ref The introduction of AFI_L2VPN prefix makes usage of AFI_ETHER deprecated and is of no usage currently. The former replaces the latter one. Signed-off-by: Philippe Guibert --- bgpd/bgp_route.h | 2 +- bgpd/bgp_vty.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index da015feb21..3cd4dd59a0 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -94,7 +94,7 @@ struct bgp_info_extra struct in6_addr addr6; } un; /* cached un address */ time_t create_time; - struct prefix aux_prefix; /* AFI_ETHER: the IP addr, if family set */ + struct prefix aux_prefix; /* AFI_L2VPN: the IP addr, if family set */ } import; } vnc; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 896518fca3..aa8c3145f9 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6690,7 +6690,7 @@ bgp_show_summary_afi_safi (struct vty *vty, struct bgp *bgp, int afi, int safi, } afi++; if (! afi_wildcard || - afi == AFI_ETHER) /* special case, not handled yet */ + afi == AFI_L2VPN) /* special case, not handled yet */ afi = AFI_MAX; } From 0aa9c36c076c5069a651a6f645a49bd2bcd12174 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 3 Feb 2017 08:02:14 +0100 Subject: [PATCH 50/64] bgpd: replace AFI_ETHER reference with AFI_L2VPN ref The introduction of AFI_L2VPN prefix makes usage of AFI_ETHER deprecated and is of no usage currently. The former replaces the latter one. Signed-off-by: Philippe Guibert --- bgpd/rfapi/rfapi.c | 6 +++--- bgpd/rfapi/rfapi_import.c | 24 ++++++++++++------------ bgpd/rfapi/rfapi_monitor.c | 12 ++++++------ bgpd/rfapi/rfapi_private.h | 4 ++-- bgpd/rfapi/rfapi_rib.c | 10 +++++----- bgpd/rfapi/rfapi_vty.c | 2 +- 6 files changed, 29 insertions(+), 29 deletions(-) diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 351d4b6d5a..01a033049e 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -1451,7 +1451,7 @@ rfapi_open_inner ( #define RFD_RTINIT(rh, ary) do {\ RFD_RTINIT_AFI(rh, ary, AFI_IP);\ RFD_RTINIT_AFI(rh, ary, AFI_IP6);\ - RFD_RTINIT_AFI(rh, ary, AFI_ETHER);\ + RFD_RTINIT_AFI(rh, ary, AFI_L2VPN);\ } while(0) RFD_RTINIT(rfd, rfd->rib); @@ -3835,7 +3835,7 @@ DEFUN (debug_rfapi_show_import, &cursor)) { - if (it->imported_vpn[AFI_ETHER]) + if (it->imported_vpn[AFI_L2VPN]) { lni = lni_as_ptr; if (first_l2) @@ -3845,7 +3845,7 @@ DEFUN (debug_rfapi_show_import, first_l2 = 0; } snprintf (buf, BUFSIZ, "L2VPN LNI=%u", lni); - rfapiShowImportTable (vty, buf, it->imported_vpn[AFI_ETHER], 1); + rfapiShowImportTable (vty, buf, it->imported_vpn[AFI_L2VPN], 1); } } } diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 3601e06d54..d26d48a559 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -2077,7 +2077,7 @@ rfapiEthRouteTable2NextHopList ( it = rfapiMacImportTableGet (bgp, logical_net_id); - rt = it->imported_vpn[AFI_ETHER]; + rt = it->imported_vpn[AFI_L2VPN]; for (rn = route_top (rt); rn; rn = route_next (rn)) { @@ -3607,7 +3607,7 @@ rfapiBgpInfoFilteredImportVPN ( struct peer *peer, void *rfd, /* set for looped back routes */ struct prefix *p, - struct prefix *aux_prefix, /* AFI_ETHER: optional IP */ + struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */ afi_t afi, struct prefix_rd *prd, struct attr *attr, /* part of bgp_info */ @@ -3702,7 +3702,7 @@ rfapiBgpInfoFilteredImportVPN ( { case AFI_IP: case AFI_IP6: - case AFI_ETHER: + case AFI_L2VPN: rt = import_table->imported_vpn[afi]; break; @@ -3909,7 +3909,7 @@ rfapiBgpInfoFilteredImportVPN ( * For ethernet routes, if there is an accompanying IP address, * save it in the bi */ - if ((AFI_ETHER == afi) && aux_prefix) + if ((AFI_L2VPN == afi) && aux_prefix) { vnc_zlog_debug_verbose ("%s: setting BI's aux_prefix", __func__); @@ -4178,7 +4178,7 @@ rfapiProcessUpdate ( rfd, &pfx_mac_buf, /* prefix */ p, /* aux prefix: IP addr */ - AFI_ETHER, + AFI_L2VPN, prd, attr, type, @@ -4291,7 +4291,7 @@ rfapiProcessWithdraw ( #if DEBUG_L2_EXTRA vnc_zlog_debug_verbose - ("%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_ETHER)", + ("%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)", __func__, it); #endif @@ -4302,7 +4302,7 @@ rfapiProcessWithdraw ( rfd, &pfx_mac_buf, /* prefix */ p, /* aux_prefix: IP */ - AFI_ETHER, + AFI_L2VPN, prd, attr, type, @@ -4808,7 +4808,7 @@ rfapiDeleteRemotePrefixesIt ( vnc_zlog_debug_verbose ("%s: rn pfx=%s", __func__, buf_pfx); } - /* TBD is this valid for afi == AFI_ETHER? */ + /* TBD is this valid for afi == AFI_L2VPN? */ RFAPI_CHECK_REFCOUNT (rn, SAFI_MPLS_VPN, 1); for (bi = rn->info; bi; bi = next) @@ -5166,10 +5166,10 @@ rfapiCountAllItRoutes (int *pALRcount, /* active local routes */ rc = skiplist_next (h->import_mac, NULL, (void **) &it, &cursor)) { - total_active_local += it->local_count[AFI_ETHER]; - total_active_remote += it->remote_count[AFI_ETHER]; - total_holddown += it->holddown_count[AFI_ETHER]; - total_imported += it->imported_count[AFI_ETHER]; + total_active_local += it->local_count[AFI_L2VPN]; + total_active_remote += it->remote_count[AFI_L2VPN]; + total_holddown += it->holddown_count[AFI_L2VPN]; + total_imported += it->imported_count[AFI_L2VPN]; } } diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c index c051b9b3e0..a9e6e4f934 100644 --- a/bgpd/rfapi/rfapi_monitor.c +++ b/bgpd/rfapi/rfapi_monitor.c @@ -941,7 +941,7 @@ rfapiMonitorItNodeChanged ( __func__, import_table, it_node, buf_prefix); #endif - if (AFI_ETHER == afi) + if (AFI_L2VPN == afi) { struct rfapi_monitor_eth *m; struct skiplist *sl; @@ -1044,7 +1044,7 @@ rfapiMonitorItNodeChanged ( /* * All-routes L2 monitors */ - if (AFI_ETHER == afi) + if (AFI_L2VPN == afi) { struct rfapi_monitor_eth *e; @@ -1305,7 +1305,7 @@ rfapiMonitorEthAttachImportHd (struct bgp *bgp, struct rfapi_descriptor *rfd) pfx_mac_buf.prefixlen = 48; pfx_mac_buf.u.prefix_eth = mon->macaddr; - rn = route_node_get (it->imported_vpn[AFI_ETHER], &pfx_mac_buf); + rn = route_node_get (it->imported_vpn[AFI_L2VPN], &pfx_mac_buf); assert (rn); (void) rfapiMonitorEthAttachImport (it, rn, mon); @@ -1361,7 +1361,7 @@ rfapiMonitorEthDetachImport ( pfx_mac_buf.prefixlen = 48; pfx_mac_buf.u.prefix_eth = mon->macaddr; - rn = route_node_get (it->imported_vpn[AFI_ETHER], &pfx_mac_buf); + rn = route_node_get (it->imported_vpn[AFI_L2VPN], &pfx_mac_buf); assert (rn); #if DEBUG_L2_EXTRA @@ -1423,7 +1423,7 @@ rfapiMonitorEthAdd ( if (!RFAPI_0_ETHERADDR (macaddr)) { - rn = route_node_get (it->imported_vpn[AFI_ETHER], &pfx_mac_buf); + rn = route_node_get (it->imported_vpn[AFI_L2VPN], &pfx_mac_buf); assert (rn); } @@ -1635,7 +1635,7 @@ rfapiMonitorCallbacksOff (struct bgp *bgp) /* * The actual route table */ - rt = it->imported_vpn[AFI_ETHER]; + rt = it->imported_vpn[AFI_L2VPN]; /* * Find non-0 monitors (i.e., actual addresses, not FTD monitors) diff --git a/bgpd/rfapi/rfapi_private.h b/bgpd/rfapi/rfapi_private.h index 8ac2966bfe..a5e3970549 100644 --- a/bgpd/rfapi/rfapi_private.h +++ b/bgpd/rfapi/rfapi_private.h @@ -133,7 +133,7 @@ struct rfapi_descriptor uint32_t flags; #define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP 0x00000001 #define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP6 0x00000002 -#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_ETHER 0x00000004 +#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_L2VPN 0x00000004 #define RFAPI_HD_FLAG_PROVISIONAL 0x00000008 #define RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY 0x00000010 #define RFAPI_HD_FLAG_IS_VRF 0x00000012 @@ -142,7 +142,7 @@ struct rfapi_descriptor #define RFAPI_QUEUED_FLAG(afi) ( \ ((afi) == AFI_IP)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP: \ (((afi) == AFI_IP6)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_IP6: \ - (((afi) == AFI_ETHER)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_ETHER: \ + (((afi) == AFI_L2VPN)? RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_L2VPN: \ (assert(0), 0) ))) diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 8e5d47415f..d633023dcf 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -916,7 +916,7 @@ process_pending_node ( vnc_zlog_debug_verbose ("%s: afi=%d, %s pn->info=%p", __func__, afi, buf_prefix, pn->info); - if (AFI_ETHER != afi) + if (AFI_L2VPN != afi) { rfapiQprefix2Rprefix (&pn->p, &hp); } @@ -1246,7 +1246,7 @@ callback: else { new->prefix = hp; - if (AFI_ETHER == afi) + if (AFI_L2VPN == afi) { /* hp is 0; need to set length to match AF of vn */ new->prefix.length = @@ -1334,7 +1334,7 @@ callback: else { new->prefix = hp; - if (AFI_ETHER == afi) + if (AFI_L2VPN == afi) { /* hp is 0; need to set length to match AF of vn */ new->prefix.length = @@ -1976,7 +1976,7 @@ rfapiRibPreload ( continue; } - afi = AFI_ETHER; + afi = AFI_L2VPN; rfapiL2o2Qprefix (pL2o, &pfx); } else @@ -2181,7 +2181,7 @@ rfapiRibPendingDeleteRoute ( vnc_zlog_debug_verbose ("%s: entry, it=%p, afi=%d, it_node=%p, pfx=%s", __func__, it, afi, it_node, buf); - if (AFI_ETHER == afi) + if (AFI_L2VPN == afi) { /* * ethernet import tables are per-LNI and each ethernet monitor diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 997f1d3c34..be7fbc63a2 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -1329,7 +1329,7 @@ rfapiShowRemoteRegistrationsIt ( int show_local, int show_remote, int show_imported, /* either/or */ - uint32_t *pLni) /* AFI_ETHER only */ + uint32_t *pLni) /* AFI_L2VPN only */ { afi_t afi; int printed_rtlist_hdr = 0; From d5c8a0cecfe22a5073db66801b492eb2f3aafcae Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 3 Feb 2017 08:28:57 +0100 Subject: [PATCH 51/64] lib: append prefix_ for mac handling functions This commit is changing the function naming for mac handling functions. Signed-off-by: Philippe Guibert --- lib/prefix.c | 4 ++-- lib/prefix.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index 73af29ead3..054ba814a5 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1051,7 +1051,7 @@ static uint8_t convertchartohexa(uint8_t * hexa, int *error) * format accepted: AA:BB:CC:DD:EE:FF * if mac parameter is null, then check only */ -int str2mac(const char *str, char *mac) +int prefix_str2mac(const char *str, char *mac) { unsigned int k = 0, i, j; uint8_t *ptr, *ptr2; @@ -1119,7 +1119,7 @@ int str2mac(const char *str, char *mac) return 1; } -char *mac2str(char *mac, char *buf, int size) +char *prefix_mac2str(const char *mac, char *buf, int size) { char *ptr; diff --git a/lib/prefix.h b/lib/prefix.h index 53cf9208e5..e384e07277 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -327,8 +327,8 @@ extern void masklen2ip6 (const int, struct in6_addr *); extern const char *inet6_ntoa (struct in6_addr); -extern int str2mac(const char *str, char *mac); -extern char *mac2str(char *mac, char *buf, int size); +extern int prefix_str2mac(const char *str, char *mac); +extern char *prefix_mac2str(const char *mac, char *buf, int size); static inline int ipv6_martian (struct in6_addr *addr) { From 7acff3e73536f9f5afc3d7ffbbe1d72c2cbfc38e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 3 Feb 2017 09:10:08 +0100 Subject: [PATCH 52/64] bgpd: reflect mac handling change of apis to bgpd As the prefix call function for mac handling has prefix_ prepended before, the change must be propagated to all locations where those functions are called. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr_evpn.c | 2 +- bgpd/bgp_route.c | 6 +++--- bgpd/rfapi/rfapi_vty.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 929b4c17c3..f60784e708 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -171,7 +171,7 @@ char *ecom_mac2str(char *ecom_mac) en = ecom_mac; en += 2; - return mac2str(en, NULL, 0); + return prefix_mac2str(en, NULL, 0); } /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 3d23fa4ca6..55823a272f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -4502,7 +4502,7 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, vty_out (vty, "%% Malformed ESI%s", VTY_NEWLINE); return CMD_WARNING; } - if( routermac && str2mac (routermac, NULL) == 0) + if( routermac && prefix_str2mac (routermac, NULL) == 0) { vty_out (vty, "%% Malformed Router MAC%s", VTY_NEWLINE); return CMD_WARNING; @@ -4568,7 +4568,7 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str, if( routermac) { bgp_static->router_mac = XCALLOC (MTYPE_ATTR, ETHER_ADDR_LEN+1); - str2mac (routermac, bgp_static->router_mac); + prefix_str2mac (routermac, bgp_static->router_mac); } if (gwip) prefix_copy (&bgp_static->gatewayIp, &gw_ip); @@ -10531,7 +10531,7 @@ bgp_config_write_network_evpn (struct vty *vty, struct bgp *bgp, char *esi = NULL; if(bgp_static->router_mac) - macrouter = mac2str(bgp_static->router_mac, NULL, 0); + macrouter = prefix_mac2str(bgp_static->router_mac, NULL, 0); if(bgp_static->eth_s_id) esi = esi2str(bgp_static->eth_s_id); p = &rn->p; diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index be7fbc63a2..22489e87e2 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -314,7 +314,7 @@ rfapiL2o2Qprefix (struct rfapi_l2address_option *l2o, struct prefix *pfx) char * rfapiEthAddr2Str (const struct ethaddr *ea, char *buf, int bufsize) { - return mac2str (ea->octet, buf, bufsize); + return prefix_mac2str (ea->octet, buf, bufsize); } int From db42a173d67868b522b3a3a035372f582152b3c1 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 9 Feb 2017 08:42:32 +0100 Subject: [PATCH 53/64] lib: simplify str2mac and use struct ethaddr structure This commit simplified the string to mac conversion, since it uses sscanf, instead of depicting each incoming character one by one, and doing self analysis. Also,this commit changes the internal usage of the mac address representation in mac handling function. Signed-off-by: Lou Berger Signed-off-by: Philippe Guibert --- lib/prefix.c | 104 +++++++++------------------------------------------ lib/prefix.h | 4 +- 2 files changed, 19 insertions(+), 89 deletions(-) diff --git a/lib/prefix.c b/lib/prefix.c index 054ba814a5..8948a2ac19 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1022,104 +1022,34 @@ inet6_ntoa (struct in6_addr addr) return buf; } - -static uint8_t convertchartohexa(uint8_t * hexa, int *error) -{ - if ((*hexa == '0') || (*hexa == '1') || (*hexa == '2') || - (*hexa == '3') || (*hexa == '4') || (*hexa == '5') || - (*hexa == '6') || (*hexa == '7') || (*hexa == '8') - || (*hexa == '9')) - return (uint8_t) (*hexa) - '0'; - if ((*hexa == 'a') || (*hexa == 'A')) - return 0xa; - if ((*hexa == 'b') || (*hexa == 'B')) - return 0xb; - if ((*hexa == 'c') || (*hexa == 'C')) - return 0xc; - if ((*hexa == 'd') || (*hexa == 'D')) - return 0xd; - if ((*hexa == 'e') || (*hexa == 'E')) - return 0xe; - if ((*hexa == 'f') || (*hexa == 'F')) - return 0xf; - *error = -1; - return 0; -} - /* 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 */ -int prefix_str2mac(const char *str, char *mac) +int prefix_str2mac(const char *str, struct ethaddr *mac) { - unsigned int k = 0, i, j; - uint8_t *ptr, *ptr2; - size_t len; - uint8_t car; - + unsigned int a[6]; + int i; + if (!str) return 0; - if (str[0] == ':' && str[1] == '\0') - return 1; - - i = 0; - ptr = (uint8_t *) str; - while (i < 6) { - uint8_t temp[5]; - int error = 0; - ptr2 = (uint8_t *) strchr((const char *)ptr, ':'); - if (ptr2 == NULL) { - /* if last occurence return ok */ - if (i != 5) { - zlog_err("[%s]: format non recognized", mac); - return 0; - } - len = strlen((char *)ptr); - } else { - len = ptr2 - ptr; - } - if (len > 5) { - zlog_err("[%s]: format non recognized", mac); + 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 */ return 0; } - memcpy(temp, ptr, len); - for (j = 0; j < len; j++) { - if (k >= ETHER_ADDR_LEN) - return 0; - if (mac) - mac[k] = 0; - car = convertchartohexa(&temp[j], &error); - if (error) - return 0; - if (mac) - mac[k] = car << 4; - j++; - if (j == len) - return 0; - car = convertchartohexa(&temp[j], &error) & 0xf; - if (error) - return 0; - if (mac) - mac[k] |= car & 0xf; - k++; - i++; - } - ptr = ptr2; - if (ptr == NULL) - break; - ptr++; - } - if (mac && 0) { - zlog_err("leave correct : %02x:%02x:%02x:%02x:%02x:%02x", - mac[0] & 0xff, mac[1] & 0xff, mac[2] & 0xff, - mac[3] & 0xff, mac[4] & 0xff, mac[5] & 0xff); - } + /* valid mac address */ + if (!mac) + return 1; + for (i = 0; i < 6; ++i) + mac->octet[i] = a[i] & 0xff; return 1; } -char *prefix_mac2str(const char *mac, char *buf, int size) +char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size) { char *ptr; @@ -1133,8 +1063,8 @@ char *prefix_mac2str(const char *mac, char *buf, int size) ptr = buf; } snprintf(ptr, (ETHER_ADDR_STRLEN), - "%02x:%02x:%02x:%02x:%02x:%02x", (uint8_t) mac[0], - (uint8_t) mac[1], (uint8_t) mac[2], (uint8_t) mac[3], - (uint8_t) mac[4], (uint8_t) mac[5]); + "%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]); return ptr; } diff --git a/lib/prefix.h b/lib/prefix.h index e384e07277..eb3ae3dafb 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -327,8 +327,8 @@ extern void masklen2ip6 (const int, struct in6_addr *); extern const char *inet6_ntoa (struct in6_addr); -extern int prefix_str2mac(const char *str, char *mac); -extern char *prefix_mac2str(const char *mac, char *buf, int size); +extern int prefix_str2mac(const char *str, struct ethaddr *mac); +extern char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size); static inline int ipv6_martian (struct in6_addr *addr) { From 31689a53f1314f803f50fe07c25a0e51c46a5279 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 9 Feb 2017 08:44:13 +0100 Subject: [PATCH 54/64] bgpd: change str2mac call api With the changed API, some adaptations are done in rfapi code, and in bgpd evpn code. For evpn code, the internal storage of routermac addr is kept as struct ethaddr structure. Also the evpn add_routermac api has as incoming parameter a struct ethaddr param. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr_evpn.c | 6 +++--- bgpd/bgp_attr_evpn.h | 3 +-- bgpd/bgp_route.h | 2 +- bgpd/rfapi/rfapi_vty.c | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index f60784e708..93b3c9390b 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -34,7 +34,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_evpn.h" -void bgp_add_routermac_ecom(struct attr *attr, char *routermac) +void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac) { struct ecommunity_val routermac_ecom; @@ -42,7 +42,7 @@ void bgp_add_routermac_ecom(struct attr *attr, char *routermac) memset(&routermac_ecom, 0, sizeof(struct ecommunity_val)); routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN; routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC; - memcpy(&routermac_ecom.val[2], routermac, ETHER_ADDR_LEN); + memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN); if (!attr->extra->ecommunity) attr->extra->ecommunity = ecommunity_new(); ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom); @@ -171,7 +171,7 @@ char *ecom_mac2str(char *ecom_mac) en = ecom_mac; en += 2; - return prefix_mac2str(en, NULL, 0); + return prefix_mac2str((struct ethaddr *)en, NULL, 0); } /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */ diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 7fa7256ca0..e6da7e7080 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -50,11 +50,10 @@ struct bgp_route_evpn { }; extern int str2esi(const char *str, struct eth_segment_id *id); -extern int str2mac(const char *str, char *mac); extern char *esi2str(struct eth_segment_id *id); extern char *ecom_mac2str(char *ecom_mac); -extern void bgp_add_routermac_ecom(struct attr *attr, char *routermac); +extern void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac); extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, struct prefix *dst); #endif /* _QUAGGA_BGP_ATTR_EVPN_H */ diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 3cd4dd59a0..e75978d003 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -206,7 +206,7 @@ struct bgp_static /* EVPN */ struct eth_segment_id *eth_s_id; - char *router_mac; + struct ethaddr *router_mac; uint16_t encap_tunneltype; struct prefix gatewayIp; }; diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 22489e87e2..55ad036f28 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -314,7 +314,7 @@ rfapiL2o2Qprefix (struct rfapi_l2address_option *l2o, struct prefix *pfx) char * rfapiEthAddr2Str (const struct ethaddr *ea, char *buf, int bufsize) { - return prefix_mac2str (ea->octet, buf, bufsize); + return prefix_mac2str (ea, buf, bufsize); } int From c298dae25906c33d61f86235c39380212f48a138 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 9 Feb 2017 09:09:54 +0100 Subject: [PATCH 55/64] bgpd: fix overlay index comparison To know if overlay index is the same between two route information, then the two overlay index field is compared. If both fields are set to null, then the comparison should be equal, then return true, which was not done. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 3a3cefda59..929a9fb4ad 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -429,7 +429,7 @@ overlay_index_same(const struct attr_extra *ae1, const struct attr_extra *ae2) if(!ae2 && ae1) return false; if(!ae1 && !ae2) - return false; + return true; return !memcmp(&(ae1->evpn_overlay), &(ae2->evpn_overlay), sizeof(struct overlay_index)); } From 6e6fd6d1177caec35f76ab31a75e5c2164ebf63b Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 9 Feb 2017 09:12:21 +0100 Subject: [PATCH 56/64] bgpd: remove useless white space character in evpn function declaration Some tabulation replaces the white space used for the declaration of this evpn function. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index bd9d7daf4d..015039c6cd 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -304,7 +304,7 @@ extern size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi); extern void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, - u_char *tag, int, u_int32_t, struct attr *); + u_char *tag, int, u_int32_t, struct attr *); extern void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt); static inline int From 20b80273cf421975a58840b87254df5f58089576 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 9 Feb 2017 09:23:23 +0100 Subject: [PATCH 57/64] bgpd: simplify str2esi function The commit replaces the char-by-char handling function by sscanf routine usage. This implementation is simplified and does the same. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr_evpn.c | 96 ++++++-------------------------------------- 1 file changed, 13 insertions(+), 83 deletions(-) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 93b3c9390b..edfeeada7b 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -49,29 +49,6 @@ void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac) } } -static uint8_t convertchartohexa(uint8_t * hexa, int *error) -{ - if ((*hexa == '0') || (*hexa == '1') || (*hexa == '2') || - (*hexa == '3') || (*hexa == '4') || (*hexa == '5') || - (*hexa == '6') || (*hexa == '7') || (*hexa == '8') - || (*hexa == '9')) - return (uint8_t) (*hexa) - '0'; - if ((*hexa == 'a') || (*hexa == 'A')) - return 0xa; - if ((*hexa == 'b') || (*hexa == 'B')) - return 0xb; - if ((*hexa == 'c') || (*hexa == 'C')) - return 0xc; - if ((*hexa == 'd') || (*hexa == 'D')) - return 0xd; - if ((*hexa == 'e') || (*hexa == 'E')) - return 0xe; - if ((*hexa == 'f') || (*hexa == 'F')) - return 0xf; - *error = -1; - return 0; -} - /* converts to an esi * returns 1 on success, 0 otherwise * format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ @@ -79,70 +56,23 @@ static uint8_t convertchartohexa(uint8_t * hexa, int *error) */ int str2esi(const char *str, struct eth_segment_id *id) { - unsigned int k = 0, i, j; - uint8_t *ptr, *ptr2; - size_t len; - uint8_t car; + unsigned int a[ESI_LEN]; + int i; if (!str) return 0; - if (str[0] == ':' && str[1] == '\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_LEN) + { + /* error in incoming str length */ + return 0; + } + /* valid mac address */ + if (!id) return 1; - - i = 0; - ptr = (uint8_t *) str; - while (i < 10) { - uint8_t temp[5]; - int error = 0; - ptr2 = (uint8_t *) strchr((const char *)ptr, ':'); - if (ptr2 == NULL) { - /* if last occurence return ok */ - if (i != 9) { - zlog_err("[%s]: format non recognized", str); - return 0; - } - len = strlen((char *)ptr); - } else { - len = ptr2 - ptr; - } - memcpy(temp, ptr, len); - if (len > 5) { - zlog_err("[%s]: format non recognized", str); - return 0; - } - for (j = 0; j < len; j++) { - if (k >= ESI_LEN) - return 0; - if (id) - id->val[k] = 0; - car = convertchartohexa(&temp[j], &error); - if (error) - return 0; - if (id) - id->val[k] = car << 4; - j++; - if (j == len) - return 0; - car = convertchartohexa(&temp[j], &error) & 0xf; - if (error) - return 0; - if (id) - id->val[k] |= car & 0xf; - k++; - i++; - } - ptr = ptr2; - if (ptr == NULL) - break; - ptr++; - } - if (id && 0) { - zlog_err("leave correct : %02x:%02x:%02x:%02x:%02x", - id->val[0], id->val[1], id->val[2], id->val[3], - id->val[4]); - zlog_err("%02x:%02x:%02x:%02x:%02x", id->val[5], id->val[6], - id->val[7], id->val[8], id->val[9]); - } + for (i = 0; i < ESI_LEN; ++i) + id->val[i] = a[i] & 0xff; return 1; } From e2858b13a9f2faf4b5e44021ce206facc43efc19 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 9 Feb 2017 09:26:30 +0100 Subject: [PATCH 58/64] bgpd: fix address-family display for l2vpn evpn When configuring l2vpn evpn address-family, the show running indicates that the address-family l2vpn evpn address-family has been configured, and not evpn, as it was done before this commit. This is a bug fix. Signed-off-by: Philippe Guibert --- bgpd/bgpd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 627d019523..3512167b02 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -7224,7 +7224,7 @@ bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi, else if (afi == AFI_L2VPN) { if (safi == SAFI_EVPN) - vty_out (vty, "evpn"); + vty_out (vty, "l2vpn evpn"); } vty_out (vty, "%s", VTY_NEWLINE); From 43b4350ca7efa79f393cf68c62b5be5614ac9a11 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 14 Feb 2017 11:54:33 +0100 Subject: [PATCH 59/64] lib: prefix2str initialises incoming buffer in case erroneous EVPN pfx In the case, evpn prefix is requested to be transformed into string, and if the evpn prefix is not an evpn route type 5 entry, then the prefix is returning an initialised string that mentions the vpn prefix is unknown. Signed-off-by: Philippe Guibert --- lib/prefix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/prefix.c b/lib/prefix.c index 8948a2ac19..19cf7dd8f9 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -880,6 +880,10 @@ prefix2str (union prefixconstptr pu, char *str, int size) buf, PREFIX2STR_BUFFER), p->prefixlen); } + else + { + sprintf (str, "UNK AF_ETHER prefix"); + } break; default: sprintf (str, "UNK prefix"); From 8ec21cf12c25474f834254d49cdde0aac8642aab Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 14 Feb 2017 12:11:29 +0100 Subject: [PATCH 60/64] bgpd: set the returned buffer to '\0' in case is returns nothing In the case where extended communities to str function is called with a filtering mecanism, then the case that the returned buffer is not inited may happen. Hence the change done. Signed-off-by: Philippe Guibert --- bgpd/bgp_ecommunity.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index a5949728c2..5d4ba78c75 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -643,6 +643,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter) /* Prepare buffer. */ str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1); str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1; + str_buf[0] = '\0'; str_pnt = 0; for (i = 0; i < ecom->size; i++) @@ -673,7 +674,6 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter) case ECOMMUNITY_ENCODE_OPAQUE: if(filter == ECOMMUNITY_ROUTE_TARGET) { - first = 0; continue; } if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) @@ -693,7 +693,6 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter) case ECOMMUNITY_ENCODE_EVPN: if(filter == ECOMMUNITY_ROUTE_TARGET) { - first = 0; continue; } if (*pnt == ECOMMUNITY_SITE_ORIGIN) @@ -829,7 +828,6 @@ extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *ecom, { u_int8_t *p; int c; - struct ecommunity_val *ecom_val; /* If the value already exists in the structure return 0. */ c = 0; From 63ca1cde19aaf20d6f1492bf8dad7583b1b6c21f Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 16 Feb 2017 15:11:04 +0100 Subject: [PATCH 61/64] bgpd: restore pre-evpn output behavior This commit is displaying all the ECs from one entry in rfapi code. Signed-off-by: Philippe Guibert --- bgpd/rfapi/rfapi_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 55ad036f28..53b38516e6 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -472,7 +472,7 @@ rfapi_vty_out_vncinfo ( if (bi->attr && bi->attr->extra && bi->attr->extra->ecommunity) { s = ecommunity_ecom2str (bi->attr->extra->ecommunity, - ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); vty_out (vty, " EC{%s}", s); XFREE (MTYPE_ECOMMUNITY_STR, s); } From 66ef4ee487e6477936a122ad12f09ce9bcfb7cf5 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 16 Feb 2017 15:12:22 +0100 Subject: [PATCH 62/64] lib: restore pre-evpn output behavior If an EVPN entry is detected, and type is not route type 5, displays the Ethernet MAC configured, as it was before evpn is introduced. Signed-off-by: Philippe Guibert --- lib/prefix.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/prefix.c b/lib/prefix.c index 19cf7dd8f9..dec22a44a3 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -883,6 +883,11 @@ prefix2str (union prefixconstptr pu, char *str, int size) else { sprintf (str, "UNK AF_ETHER prefix"); + snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d", + p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1], + p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3], + p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5], + p->prefixlen); } break; default: From 9972b54e63c80ca54789aedeb4c9b711b96783a7 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 16 Feb 2017 17:09:46 +0100 Subject: [PATCH 63/64] bgpd: initialise ecom sub field str when setting routermac In order to avoid valgrind issue, the str field is initialised. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr_evpn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index edfeeada7b..be97ffda69 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -46,6 +46,7 @@ void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac) if (!attr->extra->ecommunity) attr->extra->ecommunity = ecommunity_new(); ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom); + ecommunity_str (attr->extra->ecommunity); } } From f47195ae584424123915172d18bef2ef8ec6179e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 17 Feb 2017 08:57:37 +0100 Subject: [PATCH 64/64] bgpd: revert some RT ecom filtering to fix valgrind id'ed error and potential misreporting. This commits revert the call of ecommunity_ecom2str without filtering. Signed-off-by: Lou Berger --- bgpd/bgp_ecommunity.c | 2 +- bgpd/rfapi/rfapi.c | 4 ++-- bgpd/rfapi/rfapi_import.c | 4 ++-- bgpd/rfapi/rfapi_vty.c | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 5d4ba78c75..c80966ec6d 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -213,7 +213,7 @@ ecommunity_intern (struct ecommunity *ecom) find->refcnt++; if (! find->str) - find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY, ECOMMUNITY_ROUTE_TARGET); + find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY, 0); return find; } diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 01a033049e..99d26cf13c 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -1733,7 +1733,7 @@ rfapi_query_inner ( __func__, rfd, buf, ppNextHopEntry); s = ecommunity_ecom2str(rfd->import_table->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); vnc_zlog_debug_verbose("%s rfd->import_table=%p, rfd->import_table->rt_import_list: %s", __func__, rfd->import_table, s); XFREE (MTYPE_ECOMMUNITY_STR, s); } @@ -3809,7 +3809,7 @@ DEFUN (debug_rfapi_show_import, for (it = h->imports; it; it = it->next) { s = ecommunity_ecom2str (it->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); vty_out (vty, "Import Table %p, RTs: %s%s", it, s, VTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, s); diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index d26d48a559..4a05018d23 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -1091,8 +1091,8 @@ rfapiEcommunitiesIntersect (struct ecommunity *e1, struct ecommunity *e2) { char *s1, *s2; - s1 = ecommunity_ecom2str (e1, ECOMMUNITY_FORMAT_DISPLAY, ECOMMUNITY_ROUTE_TARGET); - s2 = ecommunity_ecom2str (e2, ECOMMUNITY_FORMAT_DISPLAY, ECOMMUNITY_ROUTE_TARGET); + s1 = ecommunity_ecom2str (e1, ECOMMUNITY_FORMAT_DISPLAY, 0); + s2 = ecommunity_ecom2str (e2, ECOMMUNITY_FORMAT_DISPLAY, 0); vnc_zlog_debug_verbose ("%s: e1[%s], e2[%s]", __func__, s1, s2); XFREE (MTYPE_ECOMMUNITY_STR, s1); XFREE (MTYPE_ECOMMUNITY_STR, s2); diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 53b38516e6..1f3066b5c5 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -676,7 +676,7 @@ rfapiPrintBi (void *stream, struct bgp_info *bi) if (bi->attr->extra->ecommunity) { s = ecommunity_ecom2str (bi->attr->extra->ecommunity, - ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); r = snprintf (p, REMAIN, " %s", s); INCP; XFREE (MTYPE_ECOMMUNITY_STR, s); @@ -1433,7 +1433,7 @@ rfapiShowRemoteRegistrationsIt ( } s = ecommunity_ecom2str (it->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); if (pLni) { @@ -1807,7 +1807,7 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd) { s = ecommunity_ecom2str (rfd->rt_export_list, - ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); vty_out (vty, " Export %s%s", s, HVTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, s); } @@ -1820,7 +1820,7 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd) if (rfd->import_table) { s = ecommunity_ecom2str (rfd->import_table->rt_import_list, - ECOMMUNITY_FORMAT_ROUTE_MAP, ECOMMUNITY_ROUTE_TARGET); + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); vty_out (vty, " Import %s%s", s, HVTY_NEWLINE); XFREE (MTYPE_ECOMMUNITY_STR, s); }