From 23aa35ade57501a408fa57f346450a40f1b0158c Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Tue, 28 Sep 2021 11:18:43 -0700 Subject: [PATCH] bgpd: initial batch of evpn lttng tracepoints Low overhead bgp-evpn TPs have been added which push data out in a binary format - >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> root@switch:~# lttng list --userspace |grep "frr_bgp:evpn" frr_bgp:evpn_mh_nh_rmac_zsend (loglevel: TRACE_DEBUG_LINE (13)) (type: tracepoint) frr_bgp:evpn_mh_nh_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint) frr_bgp:evpn_mh_nhg_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint) frr_bgp:evpn_mh_vtep_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint) frr_bgp:evpn_bum_vtep_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint) frr_bgp:evpn_mac_ip_zsend (loglevel: TRACE_INFO (6)) (type: tracepoint) root@switch:~# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> In addition to the tracepoints a babeltrace python plugin for pretty printing (binary data is converted into grepable strings). Sample usage - frr_babeltrace.py trace_path Sample tracepoint output - >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1. frr_bgp: evpn_mac_ip_zsend frr_bgp:evpn_mac_ip_zsend {'action': 'add', 'vni': 1007, 'mac': '00:02:00:00:00:04', 'ip': 'fe80::202:ff:fe00:4', 'vtep': '27.0.0.15', 'esi': '03:44:38:39:ff:ff:01:00:00:02'} 2. frr_bgp: evpn_mh_vtep_zsend frr_bgp:evpn_mh_vtep_zsend {'action': 'add', 'esi': '03:44:38:39:ff:ff:01:00:00:02', 'vtep': '27.0.0.16'} 3. frr_bgp: evpn_mh_nhg_zsend frr_bgp:evpn_mh_nhg_zsend {'action': 'add', 'type': 'v4', 'nhg': 74999998, 'esi': '03:44:38:39:ff:ff:01:00:00:02', 'vrf': 85} 4. frr_bgp: evpn_mh_nh_zsend frr_bgp:evpn_mh_nh_zsend {'nhg': 74999998, 'vtep': '27.0.0.16', 'svi': 93} 5. frr_bgp: evpn_mh_nh_rmac_zsend frr_bgp:evpn_mh_nh_rmac_zsend {'action': 'add', 'vrf': 85, 'nh': '::ffff:1b00:12', 'rmac': '00:02:00:00:00:50'} >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Signed-off-by: Anuradha Karuppiah --- bgpd/bgp_evpn.c | 6 ++ bgpd/bgp_evpn_mh.c | 15 ++++ bgpd/bgp_evpn_mh.h | 2 + bgpd/bgp_trace.h | 90 ++++++++++++++++++++++ tools/frr_babeltrace.py | 163 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 276 insertions(+) create mode 100755 tools/frr_babeltrace.py diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 3219ae13b5..ea54c14222 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -54,6 +54,7 @@ #include "bgpd/bgp_mac.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_nht.h" +#include "bgpd/bgp_trace.h" /* * Definitions and external declarations. @@ -653,6 +654,9 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, &p->prefix.macip_addr.mac, &p->prefix.macip_addr.ip, flags, seq, &remote_vtep_ip); + frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip, + esi); + return zclient_send_message(zclient); } @@ -703,6 +707,8 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, add ? "ADD" : "DEL", vpn->vni, &p->prefix.imet_addr.ip.ipaddr_v4); + frrtrace(3, frr_bgp, evpn_bum_vtep_zsend, add, vpn, p); + return zclient_send_message(zclient); } diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 34094a0bde..9316d218a2 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -50,6 +50,7 @@ #include "bgpd/bgp_label.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_mpath.h" +#include "bgpd/bgp_trace.h" static void bgp_evpn_local_es_down(struct bgp *bgp, struct bgp_evpn_es *es); @@ -1225,6 +1226,8 @@ static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_new(struct bgp_evpn_es *es, es_vtep->es = es; es_vtep->vtep_ip.s_addr = vtep_ip.s_addr; + inet_ntop(AF_INET, &es_vtep->vtep_ip, es_vtep->vtep_str, + sizeof(es_vtep->vtep_str)); listnode_init(&es_vtep->es_listnode, es_vtep); listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode); @@ -1301,6 +1304,8 @@ static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp, zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add ? "ADD" : "DEL", es->esi_str, &es_vtep->vtep_ip); + frrtrace(3, frr_bgp, evpn_mh_vtep_zsend, add, es, es_vtep); + return zclient_send_message(zclient); } @@ -2522,6 +2527,8 @@ static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf, es_vrf->bgp_vrf->vrf_id, v4_nhg ? "v4_nhg" : "v6_nhg", nhg_id); + frrtrace(4, frr_bgp, evpn_mh_nhg_zsend, true, v4_nhg, nhg_id, es_vrf); + /* only the gateway ip changes for each NH. rest of the params * are constant */ @@ -2558,6 +2565,8 @@ static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf, zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg.id, &es_vtep->vtep_ip, es_vrf->bgp_vrf->l3vni_svi_ifindex); + + frrtrace(3, frr_bgp, evpn_mh_nh_zsend, nhg_id, es_vtep, es_vrf); } if (!api_nhg.nexthop_num) @@ -2603,6 +2612,10 @@ static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf, es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id, v4_nhg ? "v4_nhg" : "v6_nhg", api_nhg.id); + + frrtrace(4, frr_bgp, evpn_mh_nhg_zsend, false, v4_nhg, api_nhg.id, + es_vrf); + zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg); } @@ -4202,6 +4215,8 @@ static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh *nh, bool add) nh->bgp_vrf->name, nh->nh_str); } + frrtrace(2, frr_bgp, evpn_mh_nh_rmac_zsend, add, nh); + zclient_send_message(zclient); } diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h index 22a4215664..37a46c2f0e 100644 --- a/bgpd/bgp_evpn_mh.h +++ b/bgpd/bgp_evpn_mh.h @@ -145,6 +145,8 @@ struct bgp_evpn_es_vtep { struct bgp_evpn_es *es; /* parent ES */ struct in_addr vtep_ip; + char vtep_str[INET6_ADDRSTRLEN]; + uint32_t flags; /* Rxed a Type4 route from this PE */ #define BGP_EVPNES_VTEP_ESR (1 << 0) diff --git a/bgpd/bgp_trace.h b/bgpd/bgp_trace.h index 303e06c9c9..1b740d69b5 100644 --- a/bgpd/bgp_trace.h +++ b/bgpd/bgp_trace.h @@ -35,6 +35,9 @@ #include "bgpd/bgpd.h" #include "lib/stream.h" +#include "bgpd/bgp_evpn_private.h" +#include "bgpd/bgp_evpn_mh.h" + /* clang-format off */ @@ -243,6 +246,93 @@ TRACEPOINT_EVENT( ) TRACEPOINT_LOGLEVEL(frr_bgp, bgp_dest_unlock, TRACE_INFO) +TRACEPOINT_EVENT( + frr_bgp, + evpn_mac_ip_zsend, + TP_ARGS(int, add, struct bgpevpn *, vpn, + const struct prefix_evpn *, pfx, + struct in_addr, vtep, esi_t *, esi), + TP_FIELDS( + ctf_string(action, add ? "add" : "del") + ctf_integer(vni_t, vni, vpn->vni) + ctf_array(unsigned char, mac, &pfx->prefix.macip_addr.mac, + sizeof(struct ethaddr)) + ctf_array(unsigned char, ip, &pfx->prefix.macip_addr.ip, + sizeof(struct ipaddr)) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mac_ip_zsend, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_bum_vtep_zsend, + TP_ARGS(int, add, struct bgpevpn *, vpn, + const struct prefix_evpn *, pfx), + TP_FIELDS( + ctf_string(action, add ? "add" : "del") + ctf_integer(vni_t, vni, vpn->vni) + ctf_integer_network_hex(unsigned int, vtep, + pfx->prefix.imet_addr.ip.ipaddr_v4.s_addr) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_bum_vtep_zsend, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_vtep_zsend, + TP_ARGS(bool, add, struct bgp_evpn_es *, es, + struct bgp_evpn_es_vtep *, es_vtep), + TP_FIELDS( + ctf_string(action, add ? "add" : "del") + ctf_string(esi, es->esi_str) + ctf_string(vtep, es_vtep->vtep_str) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_vtep_zsend, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_nhg_zsend, + TP_ARGS(bool, add, bool, type_v4, uint32_t, nhg_id, + struct bgp_evpn_es_vrf *, es_vrf), + TP_FIELDS( + ctf_string(action, add ? "add" : "del") + ctf_string(type, type_v4 ? "v4" : "v6") + ctf_integer(unsigned int, nhg, nhg_id) + ctf_string(esi, es_vrf->es->esi_str) + ctf_integer(int, vrf, es_vrf->bgp_vrf->vrf_id) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_nhg_zsend, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_nh_zsend, + TP_ARGS(uint32_t, nhg_id, struct bgp_evpn_es_vtep *, vtep, + struct bgp_evpn_es_vrf *, es_vrf), + TP_FIELDS( + ctf_integer(unsigned int, nhg, nhg_id) + ctf_string(vtep, vtep->vtep_str) + ctf_integer(int, svi, es_vrf->bgp_vrf->l3vni_svi_ifindex) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_nh_zsend, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_nh_rmac_zsend, + TP_ARGS(bool, add, struct bgp_evpn_nh *, nh), + TP_FIELDS( + ctf_string(action, add ? "add" : "del") + ctf_integer(int, vrf, nh->bgp_vrf->vrf_id) + ctf_string(nh, nh->nh_str) + ctf_array(unsigned char, rmac, &nh->rmac, + sizeof(struct ethaddr)) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_nh_rmac_zsend, TRACE_INFO) /* clang-format on */ #include diff --git a/tools/frr_babeltrace.py b/tools/frr_babeltrace.py new file mode 100755 index 0000000000..3058395758 --- /dev/null +++ b/tools/frr_babeltrace.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +''' +Usage: frr_babeltrace.py trace_path + +FRR pushes data into lttng tracepoints in the least overhead way possible +i.e. as binary-data/crf_arrays. These traces need to be converted into pretty +strings for easy greping etc. This script is a babeltrace python plugin for +that pretty printing. + +Copyright (C) 2021 NVIDIA Corporation +Anuradha Karuppiah + +This program 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 of the License, or (at your option) +any later version. + +This program 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 this program; see the file COPYING; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +''' + +import ipaddress +import socket +import sys + +import babeltrace + +########################### common parsers - start ############################ +def print_ip_addr(field_val): + ''' + pretty print "struct ipaddr" + ''' + if field_val[0] == socket.AF_INET: + addr = [str(fv) for fv in field_val[4:8]] + return str(ipaddress.IPv4Address('.'.join(addr))) + + if field_val[0] == socket.AF_INET6: + tmp = ''.join('%02x' % fb for fb in field_val[4:]) + addr = [] + while tmp: + addr.append(tmp[:4]) + tmp = tmp[4:] + addr = ':'.join(addr) + return str(ipaddress.IPv6Address(addr)) + + if not field_val[0]: + return '' + + return field_val + + +def print_mac(field_val): + ''' + pretty print "u8 mac[6]" + ''' + return ':'.join('%02x' % fb for fb in field_val) + +def print_net_ipv4_addr(field_val): + ''' + pretty print ctf_integer_network ipv4 + ''' + return str(ipaddress.IPv4Address(field_val)) + +def print_esi(field_val): + ''' + pretty print ethernet segment id, esi_t + ''' + return ':'.join('%02x' % fb for fb in field_val) + +def get_field_list(event): + ''' + only fetch fields added via the TP, skip metadata etc. + ''' + return event.field_list_with_scope(babeltrace.CTFScope.EVENT_FIELDS) + +def parse_event(event, field_parsers): + ''' + Wild card event parser; doesn't make things any prettier + ''' + field_list = get_field_list(event) + field_info = {} + for field in field_list: + if field in field_parsers: + field_parser = field_parsers.get(field) + field_info[field] = field_parser(event.get(field)) + else: + field_info[field] = event.get(field) + print(event.name, field_info) +############################ common parsers - end ############################# + +############################ evpn parsers - start ############################# +def parse_frr_bgp_evpn_mac_ip_zsend(event): + ''' + bgp evpn mac-ip parser; raw format - + ctf_array(unsigned char, mac, &pfx->prefix.macip_addr.mac, + sizeof(struct ethaddr)) + ctf_array(unsigned char, ip, &pfx->prefix.macip_addr.ip, + sizeof(struct ipaddr)) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ''' + field_parsers = {'ip': print_ip_addr, + 'mac': print_mac, + 'esi': print_esi, + 'vtep': print_net_ipv4_addr} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_bum_vtep_zsend(event): + ''' + bgp evpn bum-vtep parser; raw format - + ctf_integer_network_hex(unsigned int, vtep, + pfx->prefix.imet_addr.ip.ipaddr_v4.s_addr) + + ''' + field_parsers = {'vtep': print_net_ipv4_addr} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_mh_nh_rmac_send(event): + ''' + bgp evpn nh-rmac parser; raw format - + ctf_array(unsigned char, rmac, &nh->rmac, sizeof(struct ethaddr)) + ''' + field_parsers = {'rmac': print_mac} + + parse_event(event, field_parsers) + +############################ evpn parsers - end ############################# + +def main(): + ''' + FRR lttng trace output parser; babel trace plugin + ''' + event_parsers = {'frr_bgp:evpn_mac_ip_zsend': + parse_frr_bgp_evpn_mac_ip_zsend, + 'frr_bgp:evpn_bum_vtep_zsend': + parse_frr_bgp_evpn_bum_vtep_zsend, + 'frr_bgp:evpn_mh_nh_rmac_zsend': + parse_frr_bgp_evpn_mh_nh_rmac_send} + + # get the trace path from the first command line argument + trace_path = sys.argv[1] + + # grab events + trace_collection = babeltrace.TraceCollection() + trace_collection.add_traces_recursive(trace_path, 'ctf') + + for event in trace_collection.events: + if event.name in event_parsers: + event_parser = event_parsers.get(event.name) + event_parser(event) + else: + parse_event(event, {}) + +if __name__ == '__main__': + main()