From 9a14899b0ac8f3d9d0ce077127568f215c301f6a Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 10 Jan 2018 19:13:27 +0100 Subject: [PATCH 01/14] lib: prefix support for flowspec prefix structure is used to handle flowspec prefixes. A new AFI is introduced: AF_FLOWSPEC. A sub structure named flowspec_prefix is used in prefix to host the flowspec entry. Reason to introduce that new kind is that prefixlen from prefix structure is too short to all the flowspec needs, since NLRI can go over 0xff bytes. Signed-off-by: Philippe Guibert --- lib/memory.c | 1 + lib/memory.h | 1 + lib/prefix.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++--- lib/prefix.h | 19 ++++++++++++ lib/table.c | 12 ++++++-- 5 files changed, 112 insertions(+), 7 deletions(-) diff --git a/lib/memory.c b/lib/memory.c index 90d7d420a9..be8b100ba7 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -26,6 +26,7 @@ struct memgroup **mg_insert = &mg_first; DEFINE_MGROUP(LIB, "libfrr") DEFINE_MTYPE(LIB, TMP, "Temporary memory") +DEFINE_MTYPE(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec") static inline void mt_count_alloc(struct memtype *mt, size_t size) { diff --git a/lib/memory.h b/lib/memory.h index 6de370514a..1fbbbe4231 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -127,6 +127,7 @@ struct memgroup { DECLARE_MGROUP(LIB) DECLARE_MTYPE(TMP) +DECLARE_MTYPE(PREFIX_FLOWSPEC) extern void *qmalloc(struct memtype *mt, size_t size) diff --git a/lib/prefix.c b/lib/prefix.c index 003ce992b4..515b4dcb5e 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -539,6 +539,24 @@ int prefix_match(const struct prefix *n, const struct prefix *p) if (n->prefixlen > p->prefixlen) return 0; + if (n->family == AF_FLOWSPEC) { + /* prefixlen is unused. look at fs prefix len */ + if (n->u.prefix_flowspec.prefixlen > + p->u.prefix_flowspec.prefixlen) + return 0; + + /* Set both prefix's head pointer. */ + np = (const uint8_t *)&n->u.prefix_flowspec.ptr; + pp = (const uint8_t *)&p->u.prefix_flowspec.ptr; + + offset = n->u.prefix_flowspec.prefixlen; + + while (offset--) + if (np[offset] != pp[offset]) + return 0; + return 1; + } + /* Set both prefix's head pointer. */ np = (const uint8_t *)&n->u.prefix; pp = (const uint8_t *)&p->u.prefix; @@ -581,7 +599,6 @@ int prefix_match_network_statement(const struct prefix *n, return 1; } -/* Copy prefix from src to dest. */ void prefix_copy(struct prefix *dest, const struct prefix *src) { dest->family = src->family; @@ -600,6 +617,18 @@ void prefix_copy(struct prefix *dest, const struct prefix *src) } 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_FLOWSPEC) { + void *temp; + int len; + + len = src->u.prefix_flowspec.prefixlen; + dest->u.prefix_flowspec.prefixlen = + src->u.prefix_flowspec.prefixlen; + dest->family = src->family; + temp = XCALLOC(MTYPE_PREFIX_FLOWSPEC, len); + dest->u.prefix_flowspec.ptr = (uintptr_t)temp; + memcpy((void *)dest->u.prefix_flowspec.ptr, + (void *)src->u.prefix_flowspec.ptr, len); } else { zlog_err("prefix_copy(): Unknown address family %d", src->family); @@ -639,6 +668,15 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2) if (!memcmp(&p1->u.prefix_evpn, &p2->u.prefix_evpn, sizeof(struct evpn_addr))) return 1; + if (p1->family == AF_FLOWSPEC) { + if (p1->u.prefix_flowspec.prefixlen != + p2->u.prefix_flowspec.prefixlen) + return 0; + if (!memcmp(&p1->u.prefix_flowspec.ptr, + &p2->u.prefix_flowspec.ptr, + p2->u.prefix_flowspec.prefixlen)) + return 1; + } } return 0; } @@ -659,12 +697,30 @@ int prefix_cmp(const struct prefix *p1, const struct prefix *p2) int shift; /* Set both prefix's head pointer. */ - const uint8_t *pp1 = (const uint8_t *)&p1->u.prefix; - const uint8_t *pp2 = (const uint8_t *)&p2->u.prefix; + const uint8_t *pp1; + const uint8_t *pp2; - if (p1->family != p2->family || p1->prefixlen != p2->prefixlen) + if (p1->family != p2->family) return 1; + if (p1->family == AF_FLOWSPEC) { + pp1 = (const uint8_t *)p1->u.prefix_flowspec.ptr; + pp2 = (const uint8_t *)p2->u.prefix_flowspec.ptr; + if (p1->u.prefix_flowspec.prefixlen != + p2->u.prefix_flowspec.prefixlen) + return 1; + + offset = p1->u.prefix_flowspec.prefixlen; + while (offset--) + if (pp1[offset] != pp2[offset]) + return 1; + return 0; + } + pp1 = (const uint8_t *)&p1->u.prefix; + pp2 = (const uint8_t *)&p2->u.prefix; + + if (p1->prefixlen != p2->prefixlen) + return 1; offset = p1->prefixlen / PNBBY; shift = p1->prefixlen % PNBBY; @@ -1207,6 +1263,10 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) prefixevpn2str(p, str, size); break; + case AF_FLOWSPEC: + sprintf(str, "FS prefix"); + break; + default: sprintf(str, "UNK prefix"); break; @@ -1386,6 +1446,24 @@ unsigned prefix_hash_key(void *pp) { struct prefix copy; + if (((struct prefix *)pp)->family == AF_FLOWSPEC) { + uint32_t len; + void *temp; + + /* make sure *all* unused bits are zero, + * particularly including alignment / + * padding and unused prefix bytes. + */ + memset(©, 0, sizeof(copy)); + prefix_copy(©, (struct prefix *)pp); + len = jhash((void *)copy.u.prefix_flowspec.ptr, + copy.u.prefix_flowspec.prefixlen, + 0x55aa5a5a); + temp = (void *)copy.u.prefix_flowspec.ptr; + XFREE(MTYPE_PREFIX_FLOWSPEC, temp); + copy.u.prefix_flowspec.ptr = (uintptr_t)NULL; + return len; + } /* make sure *all* unused bits are zero, particularly including * alignment / * padding and unused prefix bytes. */ diff --git a/lib/prefix.h b/lib/prefix.h index 133264f999..4efbc5a95c 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -106,6 +106,15 @@ struct evpn_addr { #define AF_EVPN (AF_MAX + 1) #endif +#if !defined(AF_FLOWSPEC) +#define AF_FLOWSPEC (AF_MAX + 2) +#endif + +struct flowspec_prefix { + uint16_t prefixlen; /* length in bytes */ + uintptr_t ptr; +}; + /* FRR generic prefix structure. */ struct prefix { uint8_t family; @@ -122,6 +131,7 @@ struct prefix { uint8_t val[16]; uintptr_t ptr; struct evpn_addr prefix_evpn; /* AF_EVPN */ + struct flowspec_prefix prefix_flowspec; /* AF_FLOWSPEC */ } u __attribute__((aligned(8))); }; @@ -174,6 +184,13 @@ struct prefix_ptr { uintptr_t prefix __attribute__((aligned(8))); }; +/* Prefix for a Flowspec entry */ +struct prefix_fs { + uint8_t family; + uint8_t prefixlen; /* unused */ + struct flowspec_prefix prefix __attribute__((aligned(8))); +}; + struct prefix_sg { uint8_t family; uint8_t prefixlen; @@ -191,6 +208,7 @@ union prefixptr { struct prefix_ipv4 *p4; struct prefix_ipv6 *p6; struct prefix_evpn *evp; + const struct prefix_fs *fs; } __attribute__((transparent_union)); union prefixconstptr { @@ -198,6 +216,7 @@ union prefixconstptr { const struct prefix_ipv4 *p4; const struct prefix_ipv6 *p6; const struct prefix_evpn *evp; + const struct prefix_fs *fs; } __attribute__((transparent_union)); #ifndef INET_ADDRSTRLEN diff --git a/lib/table.c b/lib/table.c index bf63609bc3..3adb793891 100644 --- a/lib/table.c +++ b/lib/table.c @@ -152,10 +152,16 @@ static void route_common(const struct prefix *n, const struct prefix *p, int i; uint8_t diff; uint8_t mask; + const uint8_t *np; + const uint8_t *pp; + uint8_t *newp; - const uint8_t *np = (const uint8_t *)&n->u.prefix; - const uint8_t *pp = (const uint8_t *)&p->u.prefix; - uint8_t *newp = (uint8_t *)&new->u.prefix; + if (n->family == AF_FLOWSPEC) + return prefix_copy(new, p); + np = (const uint8_t *)&n->u.prefix; + pp = (const uint8_t *)&p->u.prefix; + + newp = (uint8_t *)&new->u.prefix; for (i = 0; i < p->prefixlen / 8; i++) { if (np[i] == pp[i]) From 7c40bf391c1d45e26b4dd342ca5fee1b0ae3fe19 Mon Sep 17 00:00:00 2001 From: jaydom Date: Mon, 23 Jan 2017 10:45:30 +0800 Subject: [PATCH 02/14] bgpd: add flowspec feature This work is derived from a work done by China-Telecom. That initial work can be found in [0]. As the gap between frr and quagga is important, a reworks has been done in the meantime. The initial work consists of bringing the following: - Bringing the client side of flowspec. - the enhancement of address-family ipv4/ipv6 flowspec - partial data path handling at reception has been prepared - the support for ipv4 flowspec or ipv6 flowspec in BGP open messages, and the internals of BGP has been done. - the memory contexts necessary for flowspec has been provisioned In addition to this work, the following has been done: - the complement of adaptation for FS safi in bgp code - the code checkstyle has been reworked so as to match frr checkstyle - the processing of IPv6 FS NLRI is prevented - the processing of FS NLRI is stopped ( temporary) [0] https://github.com/chinatelecom-sdn-group/quagga_flowspec/ Signed-off-by: Philippe Guibert Signed-off-by: jaydom --- bgpd/Makefile.am | 4 +- bgpd/bgp_attr.c | 20 +++++++ bgpd/bgp_ecommunity.h | 2 +- bgpd/bgp_flowspec.c | 78 +++++++++++++++++++++++++++ bgpd/bgp_flowspec.h | 27 ++++++++++ bgpd/bgp_flowspec_private.h | 24 +++++++++ bgpd/bgp_memory.c | 7 +++ bgpd/bgp_memory.h | 8 +++ bgpd/bgp_open.c | 11 ++++ bgpd/bgp_packet.c | 7 +++ bgpd/bgp_vty.c | 105 ++++++++++++++++++++++++++++++++---- bgpd/bgp_vty.h | 3 +- bgpd/bgpd.c | 21 ++++++++ bgpd/bgpd.h | 9 ++++ lib/command.c | 10 ++++ lib/command.h | 2 + lib/prefix.c | 2 + lib/zebra.h | 7 ++- 18 files changed, 332 insertions(+), 15 deletions(-) create mode 100644 bgpd/bgp_flowspec.c create mode 100644 bgpd/bgp_flowspec.h create mode 100644 bgpd/bgp_flowspec_private.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 5e08f82774..84b3e0183c 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -86,7 +86,7 @@ libbgp_a_SOURCES = \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \ bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c bgp_rd.c \ - bgp_keepalives.c bgp_io.c + bgp_keepalives.c bgp_io.c bgp_flowspec.c noinst_HEADERS = \ bgp_memory.h \ @@ -99,7 +99,7 @@ noinst_HEADERS = \ bgp_updgrp.h bgp_bfd.h bgp_encap_tlv.h bgp_encap_types.h \ $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \ bgp_vpn.h bgp_label.h bgp_rd.h bgp_evpn_private.h bgp_keepalives.h \ - bgp_io.h + bgp_io.h bgp_flowspec.h bgp_flowspec_private.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.c b/bgpd/bgp_attr.c index 58788a8959..639365588c 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -52,6 +52,7 @@ #endif #include "bgp_encap_types.h" #include "bgp_evpn.h" +#include "bgp_flowspec_private.h" /* Attribute strings for logging. */ static const struct message attr_str[] = { @@ -1647,6 +1648,13 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, /* Nexthop length check. */ switch (attr->mp_nexthop_len) { + case 0: + if (safi != SAFI_FLOWSPEC) { + zlog_info("%s: (%s) Wrong multiprotocol next hop length: %d", + __func__, peer->host, attr->mp_nexthop_len); + return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; + } + break; case BGP_ATTR_NHLEN_VPNV4: stream_getl(s); /* RD high */ stream_getl(s); /* RD low */ @@ -2669,6 +2677,8 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, stream_putc(s, 4); stream_put(s, &attr->mp_nexthop_global_in, 4); break; + case SAFI_FLOWSPEC: + stream_putc(s, 0); /* no nexthop for flowspec */ default: break; } @@ -2719,6 +2729,8 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, stream_put(s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN); break; + case SAFI_FLOWSPEC: + stream_putc(s, 0); /* no nexthop for flowspec */ default: break; } @@ -2756,6 +2768,14 @@ void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, } else if (safi == SAFI_LABELED_UNICAST) { /* Prefix write with label. */ stream_put_labeled_prefix(s, p, label); + } else if (safi == SAFI_FLOWSPEC) { + if (PSIZE (p->prefixlen)+2 < FLOWSPEC_NLRI_SIZELIMIT) + stream_putc(s, PSIZE (p->prefixlen)+2); + else + stream_putw(s, (PSIZE (p->prefixlen)+2)|(0xf<<12)); + stream_putc(s, 2);/* Filter type */ + stream_putc(s, p->prefixlen);/* Prefix length */ + stream_put(s, &p->u.prefix, PSIZE (p->prefixlen)); } else stream_put_prefix_addpath(s, p, addpath_encode, addpath_tx_id); } diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 4cdb8b8ac8..028b7a3166 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -53,7 +53,7 @@ #define ECOMMUNITY_SIZE 8 /* Extended Communities type flag. */ -#define ECOMMUNITY_FLAG_NON_TRANSITIVE 0x40 +#define ECOMMUNITY_FLAG_NON_TRANSITIVE 0x40 /* Extended Communities attribute. */ struct ecommunity { diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c new file mode 100644 index 0000000000..5d61175dce --- /dev/null +++ b/bgpd/bgp_flowspec.c @@ -0,0 +1,78 @@ +/* BGP FlowSpec for packet handling + * Portions: + * Copyright (C) 2017 ChinaTelecom SDN Group + * Copyright (C) 2018 6WIND + * + * FRRouting 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. + * + * FRRouting 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 + */ + +#include "math.h" + +#include +#include "prefix.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_flowspec.h" +#include "bgpd/bgp_flowspec_private.h" + +int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw) +{ + uint8_t *pnt; + uint8_t *lim; + afi_t afi; + int psize = 0; + uint8_t rlen; + struct prefix p; + + /* Start processing the NLRI - there may be multiple in the MP_REACH */ + pnt = packet->nlri; + lim = pnt + packet->length; + afi = packet->afi; + + if (afi == AFI_IP6) { + zlog_err("BGP flowspec IPv6 not supported"); + return -1; + } + + if (packet->length >= FLOWSPEC_NLRI_SIZELIMIT) { + zlog_err("BGP flowspec nlri length maximum reached (%u)", + packet->length); + return -1; + } + + for (; pnt < lim; pnt += psize) { + /* Clear prefix structure. */ + memset(&p, 0, sizeof(struct prefix)); + + /* All FlowSpec NLRI begin with length. */ + if (pnt + 1 > lim) + return -1; + + psize = rlen = *pnt++; + + /* When packet overflow occur return immediately. */ + if (pnt + psize > lim) { + zlog_err("Flowspec NLRI length inconsistent ( size %u seen)", + psize); + return -1; + } + /* TODO: validate prefix + * and add to FIB + */ + } + return 0; +} diff --git a/bgpd/bgp_flowspec.h b/bgpd/bgp_flowspec.h new file mode 100644 index 0000000000..bf019da3aa --- /dev/null +++ b/bgpd/bgp_flowspec.h @@ -0,0 +1,27 @@ +/* BGP Flowspec header for packet handling + * Copyright (C) 2018 6WIND + * + * FRRouting 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. + * + * FRRouting 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 + */ + +#ifndef _FRR_BGP_FLOWSPEC_H +#define _FRR_BGP_FLOWSPEC_H + +extern int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, + struct bgp_nlri *packet, int withdraw); + +extern void bgp_flowspec_vty_init(void); + +#endif /* _FRR_BGP_FLOWSPEC_H */ diff --git a/bgpd/bgp_flowspec_private.h b/bgpd/bgp_flowspec_private.h new file mode 100644 index 0000000000..c82bb78519 --- /dev/null +++ b/bgpd/bgp_flowspec_private.h @@ -0,0 +1,24 @@ +/* BGP Flowspec header . private structs and defines + * Copyright (C) 2018 6WIND + * + * FRRouting 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. + * + * FRRouting 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 + */ + +#ifndef _FRR_BGP_FLOWSPEC_PRIVATE_H +#define _FRR_BGP_FLOWSPEC_PRIVATE_H + +#define FLOWSPEC_NLRI_SIZELIMIT 240 + +#endif /* _FRR_BGP_FLOWSPEC_PRIVATE_H */ diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 64543ff019..4669fad3b7 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -119,3 +119,10 @@ DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information") DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT") DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT") DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP") + +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC, "BGP flowspec") +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE, "BGP flowspec rule") +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE_STR, "BGP flowspec rule str") +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_COMPILED, "BGP flowspec compiled") +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_NAME, "BGP flowspec name") +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index") diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index fae98329c6..6fa3040a19 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -115,4 +115,12 @@ DECLARE_MTYPE(BGP_EVPN) DECLARE_MTYPE(BGP_EVPN_IMPORT_RT) DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT) DECLARE_MTYPE(BGP_EVPN_MACIP) + +DECLARE_MTYPE(BGP_FLOWSPEC) +DECLARE_MTYPE(BGP_FLOWSPEC_RULE) +DECLARE_MTYPE(BGP_FLOWSPEC_RULE_STR) +DECLARE_MTYPE(BGP_FLOWSPEC_COMPILED) +DECLARE_MTYPE(BGP_FLOWSPEC_NAME) +DECLARE_MTYPE(BGP_FLOWSPEC_INDEX) + #endif /* _QUAGGA_BGP_MEMORY_H */ diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 5ec63458f5..aa98f8a557 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -146,6 +146,12 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, "capabilityErrorMultiProtocolSafi", "EVPN"); break; + case SAFI_FLOWSPEC: + json_object_string_add( + json_cap, + "capabilityErrorMultiProtocolSafi", + "flowspec"); + break; default: json_object_int_add( json_cap, @@ -187,6 +193,9 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, case SAFI_ENCAP: vty_out(vty, "SAFI ENCAP"); break; + case SAFI_FLOWSPEC: + vty_out(vty, "SAFI FLOWSPEC"); + break; case SAFI_EVPN: vty_out(vty, "SAFI EVPN"); break; @@ -1166,11 +1175,13 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability) && !peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] && !peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] && !peer->afc_nego[AFI_IP][SAFI_ENCAP] + && !peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] && !peer->afc_nego[AFI_IP6][SAFI_UNICAST] && !peer->afc_nego[AFI_IP6][SAFI_MULTICAST] && !peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] && !peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] && !peer->afc_nego[AFI_IP6][SAFI_ENCAP] + && !peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] && !peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) { zlog_err( "%s [Error] Configured AFI/SAFIs do not " diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 3c7bb65fd3..f0b30f0186 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -59,6 +59,7 @@ #include "bgpd/bgp_label.h" #include "bgpd/bgp_io.h" #include "bgpd/bgp_keepalives.h" +#include "bgpd/bgp_flowspec.h" /** * Sets marker and type fields for a BGP message. @@ -302,6 +303,8 @@ int bgp_nlri_parse(struct peer *peer, struct attr *attr, packet); case SAFI_EVPN: return bgp_nlri_parse_evpn(peer, attr, packet, mp_withdraw); + case SAFI_FLOWSPEC: + return bgp_nlri_parse_flowspec(peer, attr, packet, mp_withdraw); } return -1; } @@ -1275,6 +1278,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) peer->afc[AFI_IP][SAFI_MULTICAST]; peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] = peer->afc[AFI_IP][SAFI_LABELED_UNICAST]; + peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] = + peer->afc[AFI_IP][SAFI_FLOWSPEC]; peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = @@ -1283,6 +1288,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]; peer->afc_nego[AFI_L2VPN][SAFI_EVPN] = peer->afc[AFI_L2VPN][SAFI_EVPN]; + peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] = + peer->afc[AFI_IP6][SAFI_FLOWSPEC]; } /* When collision is detected and this peer is closed. Retrun diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 475a8ea746..a3c7994b1b 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -80,6 +80,8 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) case SAFI_MPLS_VPN: return BGP_VPNV4_NODE; break; + case SAFI_FLOWSPEC: + return BGP_FLOWSPECV4_NODE; default: /* not expected */ return BGP_IPV4_NODE; @@ -100,6 +102,8 @@ static enum node_type bgp_node_type(afi_t afi, safi_t safi) case SAFI_MPLS_VPN: return BGP_VPNV6_NODE; break; + case SAFI_FLOWSPEC: + return BGP_FLOWSPECV6_NODE; default: /* not expected */ return BGP_IPV4_NODE; @@ -128,6 +132,7 @@ afi_t bgp_node_afi(struct vty *vty) case BGP_IPV6M_NODE: case BGP_IPV6L_NODE: case BGP_VPNV6_NODE: + case BGP_FLOWSPECV6_NODE: afi = AFI_IP6; break; case BGP_EVPN_NODE: @@ -161,6 +166,10 @@ safi_t bgp_node_safi(struct vty *vty) case BGP_IPV6L_NODE: safi = SAFI_LABELED_UNICAST; break; + case BGP_FLOWSPECV4_NODE: + case BGP_FLOWSPECV6_NODE: + safi = SAFI_FLOWSPEC; + break; default: safi = SAFI_UNICAST; break; @@ -214,6 +223,8 @@ safi_t bgp_vty_safi_from_str(const char *safi_str) safi = SAFI_MPLS_VPN; else if (strmatch(safi_str, "labeled-unicast")) safi = SAFI_LABELED_UNICAST; + else if (strmatch(safi_str, "flowspec")) + safi = SAFI_FLOWSPEC; return safi; } @@ -237,6 +248,10 @@ int argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, ret = 1; if (safi) *safi = SAFI_MPLS_VPN; + } else if (argv_find(argv, argc, "flowspec", index)) { + ret = 1; + if (safi) + *safi = SAFI_FLOWSPEC; } return ret; } @@ -6645,11 +6660,11 @@ DEFPY (af_routetarget_import, } DEFUN_NOSH (address_family_ipv4_safi, - address_family_ipv4_safi_cmd, - "address-family ipv4 []", - "Enter Address Family command mode\n" - "Address Family\n" - BGP_SAFI_WITH_LABEL_HELP_STR) + address_family_ipv4_safi_cmd, + "address-family ipv4 []", + "Enter Address Family command mode\n" + "Address Family\n" + BGP_SAFI_WITH_LABEL_HELP_STR) { if (argc == 3) { @@ -6670,11 +6685,11 @@ DEFUN_NOSH (address_family_ipv4_safi, } DEFUN_NOSH (address_family_ipv6_safi, - address_family_ipv6_safi_cmd, - "address-family ipv6 []", - "Enter Address Family command mode\n" - "Address Family\n" - BGP_SAFI_WITH_LABEL_HELP_STR) + address_family_ipv6_safi_cmd, + "address-family ipv6 []", + "Enter Address Family command mode\n" + "Address Family\n" + BGP_SAFI_WITH_LABEL_HELP_STR) { if (argc == 3) { VTY_DECLVAR_CONTEXT(bgp, bgp); @@ -7943,6 +7958,8 @@ const char *afi_safi_print(afi_t afi, safi_t safi) return "IPv4 VPN"; else if (afi == AFI_IP && safi == SAFI_ENCAP) return "IPv4 Encap"; + else if (afi == AFI_IP && safi == SAFI_FLOWSPEC) + return "IPv4 Flowspec"; else if (afi == AFI_IP6 && safi == SAFI_UNICAST) return "IPv6 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) @@ -7953,6 +7970,8 @@ const char *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_IP6 && safi == SAFI_FLOWSPEC) + return "IPv6 Flowspec"; else if (afi == AFI_L2VPN && safi == SAFI_EVPN) return "L2VPN EVPN"; else @@ -7977,6 +7996,8 @@ const char *afi_safi_json(afi_t afi, safi_t safi) return "ipv4Vpn"; else if (afi == AFI_IP && safi == SAFI_ENCAP) return "ipv4Encap"; + else if (afi == AFI_IP && safi == SAFI_FLOWSPEC) + return "ipv4Flowspec"; else if (afi == AFI_IP6 && safi == SAFI_UNICAST) return "ipv6Unicast"; else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) @@ -7987,6 +8008,8 @@ const char *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_IP6 && safi == SAFI_FLOWSPEC) + return "ipv6Flowspec"; else if (afi == AFI_L2VPN && safi == SAFI_EVPN) return "l2VpnEvpn"; else @@ -9001,8 +9024,12 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, uint8_t use_json, || p->afc_recv[AFI_IP6][SAFI_MPLS_VPN] || p->afc_adv[AFI_IP6][SAFI_ENCAP] || p->afc_recv[AFI_IP6][SAFI_ENCAP] + || p->afc_adv[AFI_IP6][SAFI_FLOWSPEC] + || p->afc_recv[AFI_IP6][SAFI_FLOWSPEC] || p->afc_adv[AFI_IP][SAFI_ENCAP] || p->afc_recv[AFI_IP][SAFI_ENCAP] + || p->afc_adv[AFI_IP][SAFI_FLOWSPEC] + || p->afc_recv[AFI_IP][SAFI_FLOWSPEC] || p->afc_adv[AFI_IP][SAFI_MPLS_VPN] || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) { if (use_json) { @@ -11795,6 +11822,12 @@ static struct cmd_node bgp_evpn_node = {BGP_EVPN_NODE, static struct cmd_node bgp_evpn_vni_node = {BGP_EVPN_VNI_NODE, "%s(config-router-af-vni)# ", 1}; +static struct cmd_node bgp_flowspecv4_node = {BGP_FLOWSPECV4_NODE, + "%s(config-router-af)# ", 1}; + +static struct cmd_node bgp_flowspecv6_node = {BGP_FLOWSPECV6_NODE, + "%s(config-router-af-vpnv6)# ", 1}; + static void community_list_vty(void); static void bgp_ac_neighbor(vector comps, struct cmd_token *token) @@ -11855,6 +11888,8 @@ void bgp_vty_init(void) install_node(&bgp_vpnv6_node, NULL); install_node(&bgp_evpn_node, NULL); install_node(&bgp_evpn_vni_node, NULL); + install_node(&bgp_flowspecv4_node, NULL); + install_node(&bgp_flowspecv6_node, NULL); /* Install default VTY commands to new nodes. */ install_default(BGP_NODE); @@ -11866,6 +11901,8 @@ void bgp_vty_init(void) install_default(BGP_IPV6L_NODE); install_default(BGP_VPNV4_NODE); install_default(BGP_VPNV6_NODE); + install_default(BGP_FLOWSPECV4_NODE); + install_default(BGP_FLOWSPECV6_NODE); install_default(BGP_EVPN_NODE); install_default(BGP_EVPN_VNI_NODE); @@ -12098,6 +12135,8 @@ void bgp_vty_init(void) install_element(BGP_IPV6L_NODE, &neighbor_activate_cmd); install_element(BGP_VPNV4_NODE, &neighbor_activate_cmd); install_element(BGP_VPNV6_NODE, &neighbor_activate_cmd); + install_element(BGP_FLOWSPECV4_NODE, &neighbor_activate_cmd); + install_element(BGP_FLOWSPECV6_NODE, &neighbor_activate_cmd); install_element(BGP_EVPN_NODE, &neighbor_activate_cmd); /* "no neighbor activate" commands. */ @@ -12110,6 +12149,8 @@ void bgp_vty_init(void) install_element(BGP_IPV6L_NODE, &no_neighbor_activate_cmd); install_element(BGP_VPNV4_NODE, &no_neighbor_activate_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_activate_cmd); + install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_activate_cmd); + install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_activate_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_activate_cmd); /* "neighbor peer-group" set commands. */ @@ -12121,6 +12162,10 @@ void bgp_vty_init(void) install_element(BGP_IPV6L_NODE, &neighbor_set_peer_group_hidden_cmd); install_element(BGP_VPNV4_NODE, &neighbor_set_peer_group_hidden_cmd); install_element(BGP_VPNV6_NODE, &neighbor_set_peer_group_hidden_cmd); + install_element(BGP_FLOWSPECV4_NODE, + &neighbor_set_peer_group_hidden_cmd); + install_element(BGP_FLOWSPECV6_NODE, + &neighbor_set_peer_group_hidden_cmd); /* "no neighbor peer-group unset" commands. */ install_element(BGP_NODE, &no_neighbor_set_peer_group_cmd); @@ -12131,6 +12176,10 @@ void bgp_vty_init(void) install_element(BGP_IPV6L_NODE, &no_neighbor_set_peer_group_hidden_cmd); install_element(BGP_VPNV4_NODE, &no_neighbor_set_peer_group_hidden_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_set_peer_group_hidden_cmd); + install_element(BGP_FLOWSPECV4_NODE, + &no_neighbor_set_peer_group_hidden_cmd); + install_element(BGP_FLOWSPECV6_NODE, + &no_neighbor_set_peer_group_hidden_cmd); /* "neighbor softreconfiguration inbound" commands.*/ install_element(BGP_NODE, &neighbor_soft_reconfiguration_hidden_cmd); @@ -12151,6 +12200,14 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element(BGP_VPNV6_NODE, &neighbor_soft_reconfiguration_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_soft_reconfiguration_cmd); + install_element(BGP_FLOWSPECV4_NODE, + &neighbor_soft_reconfiguration_cmd); + install_element(BGP_FLOWSPECV4_NODE, + &no_neighbor_soft_reconfiguration_cmd); + install_element(BGP_FLOWSPECV6_NODE, + &neighbor_soft_reconfiguration_cmd); + install_element(BGP_FLOWSPECV6_NODE, + &no_neighbor_soft_reconfiguration_cmd); /* "neighbor attribute-unchanged" commands. */ install_element(BGP_NODE, &neighbor_attr_unchanged_hidden_cmd); @@ -12416,6 +12473,14 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &neighbor_route_reflector_client_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_route_reflector_client_cmd); + install_element(BGP_FLOWSPECV4_NODE, + &neighbor_route_reflector_client_cmd); + install_element(BGP_FLOWSPECV4_NODE, + &no_neighbor_route_reflector_client_cmd); + install_element(BGP_FLOWSPECV6_NODE, + &neighbor_route_reflector_client_cmd); + install_element(BGP_FLOWSPECV6_NODE, + &no_neighbor_route_reflector_client_cmd); install_element(BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd); @@ -12438,6 +12503,12 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd); install_element(BGP_VPNV6_NODE, &neighbor_route_server_client_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_route_server_client_cmd); + install_element(BGP_FLOWSPECV4_NODE, &neighbor_route_server_client_cmd); + install_element(BGP_FLOWSPECV4_NODE, + &no_neighbor_route_server_client_cmd); + install_element(BGP_FLOWSPECV6_NODE, &neighbor_route_server_client_cmd); + install_element(BGP_FLOWSPECV6_NODE, + &no_neighbor_route_server_client_cmd); /* "neighbor addpath-tx-all-paths" commands.*/ install_element(BGP_NODE, &neighbor_addpath_tx_all_paths_hidden_cmd); @@ -12665,6 +12736,10 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd); install_element(BGP_VPNV6_NODE, &neighbor_prefix_list_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_prefix_list_cmd); + install_element(BGP_FLOWSPECV4_NODE, &neighbor_prefix_list_cmd); + install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_prefix_list_cmd); + install_element(BGP_FLOWSPECV6_NODE, &neighbor_prefix_list_cmd); + install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_prefix_list_cmd); /* "neighbor filter-list" commands. */ install_element(BGP_NODE, &neighbor_filter_list_hidden_cmd); @@ -12685,6 +12760,10 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd); install_element(BGP_VPNV6_NODE, &neighbor_filter_list_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_filter_list_cmd); + install_element(BGP_FLOWSPECV4_NODE, &neighbor_filter_list_cmd); + install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_filter_list_cmd); + install_element(BGP_FLOWSPECV6_NODE, &neighbor_filter_list_cmd); + install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_filter_list_cmd); /* "neighbor route-map" commands. */ install_element(BGP_NODE, &neighbor_route_map_hidden_cmd); @@ -12705,6 +12784,10 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_route_map_cmd); install_element(BGP_VPNV6_NODE, &neighbor_route_map_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_route_map_cmd); + install_element(BGP_FLOWSPECV4_NODE, &neighbor_route_map_cmd); + install_element(BGP_FLOWSPECV4_NODE, &no_neighbor_route_map_cmd); + install_element(BGP_FLOWSPECV6_NODE, &neighbor_route_map_cmd); + install_element(BGP_FLOWSPECV6_NODE, &no_neighbor_route_map_cmd); install_element(BGP_EVPN_NODE, &neighbor_route_map_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_route_map_cmd); @@ -12853,6 +12936,8 @@ void bgp_vty_init(void) install_element(BGP_IPV6L_NODE, &exit_address_family_cmd); install_element(BGP_VPNV4_NODE, &exit_address_family_cmd); install_element(BGP_VPNV6_NODE, &exit_address_family_cmd); + install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd); + install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd); install_element(BGP_EVPN_NODE, &exit_address_family_cmd); /* "clear ip bgp commands" */ diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 7a9546e3ef..afb85f112b 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -36,11 +36,12 @@ struct bgp; #define BGP_AFI_SAFI_CMD_STR BGP_AFI_CMD_STR" "BGP_SAFI_CMD_STR #define BGP_AFI_SAFI_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_HELP_STR -#define BGP_SAFI_WITH_LABEL_CMD_STR "" +#define BGP_SAFI_WITH_LABEL_CMD_STR "" #define BGP_SAFI_WITH_LABEL_HELP_STR \ "Address Family modifier\n" \ "Address Family modifier\n" \ "Address Family modifier\n" \ + "Address Family modifier\n" \ "Address Family modifier\n" extern void bgp_vty_init(void); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 97f0ffcf2c..ad4e7dc34c 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -80,6 +80,8 @@ #include "bgpd/bgp_keepalives.h" #include "bgpd/bgp_io.h" #include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_flowspec.h" + DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)"); DEFINE_QOBJ_TYPE(bgp_master) @@ -1626,6 +1628,8 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified) PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_ENCAP], PEER_FLAG_REFLECTOR_CLIENT); + UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_FLOWSPEC], + PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_MULTICAST], @@ -1636,6 +1640,8 @@ void 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_IP6][SAFI_FLOWSPEC], + PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_L2VPN][SAFI_EVPN], PEER_FLAG_REFLECTOR_CLIENT); } @@ -3641,11 +3647,13 @@ int peer_active(struct peer *peer) if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] + || peer->afc[AFI_IP][SAFI_FLOWSPEC] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST] || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP6][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_ENCAP] + || peer->afc[AFI_IP6][SAFI_FLOWSPEC] || peer->afc[AFI_L2VPN][SAFI_EVPN]) return 1; return 0; @@ -3659,11 +3667,13 @@ int peer_active_nego(struct peer *peer) || peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP][SAFI_ENCAP] + || peer->afc_nego[AFI_IP][SAFI_FLOWSPEC] || peer->afc_nego[AFI_IP6][SAFI_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] || peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP6][SAFI_ENCAP] + || peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC] || peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) return 1; return 0; @@ -7100,6 +7110,8 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, vty_frame(vty, "ipv4 vpn"); else if (safi == SAFI_ENCAP) vty_frame(vty, "ipv4 encap"); + else if (safi == SAFI_FLOWSPEC) + vty_frame(vty, "ipv4 flowspec"); } else if (afi == AFI_IP6) { if (safi == SAFI_UNICAST) vty_frame(vty, "ipv6 unicast"); @@ -7111,6 +7123,8 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, vty_frame(vty, "ipv6 vpn"); else if (safi == SAFI_ENCAP) vty_frame(vty, "ipv6 encap"); + else if (safi == SAFI_FLOWSPEC) + vty_frame(vty, "ipv6 flowspec"); } else if (afi == AFI_L2VPN) { if (safi == SAFI_EVPN) vty_frame(vty, "l2vpn evpn"); @@ -7437,6 +7451,9 @@ int bgp_config_write(struct vty *vty) /* ENCAPv4 configuration. */ bgp_config_write_family(vty, bgp, AFI_IP, SAFI_ENCAP); + /* FLOWSPEC v4 configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP, SAFI_FLOWSPEC); + /* IPv6 unicast configuration. */ bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_UNICAST); @@ -7453,6 +7470,9 @@ int bgp_config_write(struct vty *vty) /* ENCAPv6 configuration. */ bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_ENCAP); + /* FLOWSPEC v6 configuration. */ + bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_FLOWSPEC); + /* EVPN configuration. */ bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN); @@ -7610,6 +7630,7 @@ void bgp_init(void) rfapi_init(); #endif bgp_ethernetvpn_init(); + bgp_flowspec_vty_init(); /* Access list initialize. */ access_list_init(); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 10d6e03976..40f887b86d 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -84,6 +84,8 @@ enum bgp_af_index { BGP_AF_L2VPN_EVPN, BGP_AF_IPV4_LBL_UNICAST, BGP_AF_IPV6_LBL_UNICAST, + BGP_AF_IPV4_FLOWSPEC, + BGP_AF_IPV6_FLOWSPEC, BGP_AF_MAX }; @@ -1558,6 +1560,8 @@ static inline int afindex(afi_t afi, safi_t safi) case SAFI_ENCAP: return BGP_AF_IPV4_ENCAP; break; + case SAFI_FLOWSPEC: + return BGP_AF_IPV4_FLOWSPEC; default: return BGP_AF_MAX; break; @@ -1580,6 +1584,8 @@ static inline int afindex(afi_t afi, safi_t safi) case SAFI_ENCAP: return BGP_AF_IPV6_ENCAP; break; + case SAFI_FLOWSPEC: + return BGP_AF_IPV6_FLOWSPEC; default: return BGP_AF_MAX; break; @@ -1616,6 +1622,7 @@ static inline int peer_afi_active_nego(const struct peer *peer, afi_t afi) || peer->afc_nego[afi][SAFI_LABELED_UNICAST] || peer->afc_nego[afi][SAFI_MPLS_VPN] || peer->afc_nego[afi][SAFI_ENCAP] + || peer->afc_nego[afi][SAFI_FLOWSPEC] || peer->afc_nego[afi][SAFI_EVPN]) return 1; return 0; @@ -1628,12 +1635,14 @@ static inline int peer_group_af_configured(struct peer_group *group) if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] + || peer->afc[AFI_IP][SAFI_FLOWSPEC] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST] || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP6][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_ENCAP] + || peer->afc[AFI_IP6][SAFI_FLOWSPEC] || peer->afc[AFI_L2VPN][SAFI_EVPN]) return 1; return 0; diff --git a/lib/command.c b/lib/command.c index 5697c1d812..7c7fddeea5 100644 --- a/lib/command.c +++ b/lib/command.c @@ -118,6 +118,10 @@ const char *node_names[] = { "link-params", // LINK_PARAMS_NODE, "bgp evpn vni", // BGP_EVPN_VNI_NODE, "rpki", // RPKI_NODE + "bgp ipv4 flowspec", /* BGP_FLOWSPECV4_NODE + */ + "bgp ipv6 flowspec", /* BGP_FLOWSPECV6_NODE + */ }; /* Command vector which includes some level of command lists. Normally @@ -948,6 +952,8 @@ enum node_type node_parent(enum node_type node) switch (node) { case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: + case BGP_FLOWSPECV4_NODE: + case BGP_FLOWSPECV6_NODE: case BGP_VRF_POLICY_NODE: case BGP_VNC_DEFAULTS_NODE: case BGP_VNC_NVE_GROUP_NODE: @@ -1318,6 +1324,8 @@ void cmd_exit(struct vty *vty) case BGP_IPV4L_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: + case BGP_FLOWSPECV4_NODE: + case BGP_FLOWSPECV6_NODE: case BGP_VRF_POLICY_NODE: case BGP_VNC_DEFAULTS_NODE: case BGP_VNC_NVE_GROUP_NODE: @@ -1394,6 +1402,8 @@ DEFUN (config_end, case BGP_VNC_L2_GROUP_NODE: case BGP_VPNV4_NODE: case BGP_VPNV6_NODE: + case BGP_FLOWSPECV4_NODE: + case BGP_FLOWSPECV6_NODE: case BGP_IPV4_NODE: case BGP_IPV4M_NODE: case BGP_IPV4L_NODE: diff --git a/lib/command.h b/lib/command.h index 95d8ee99df..a7fa3a1692 100644 --- a/lib/command.h +++ b/lib/command.h @@ -142,6 +142,8 @@ enum node_type { BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */ RPKI_NODE, /* RPKI node for configuration of RPKI cache server connections.*/ + BGP_FLOWSPECV4_NODE, /* BGP IPv4 FLOWSPEC Address-Family */ + BGP_FLOWSPECV6_NODE, /* BGP IPv6 FLOWSPEC Address-Family */ NODE_TYPE_MAX, /* maximum */ }; diff --git a/lib/prefix.c b/lib/prefix.c index 515b4dcb5e..ed55fac883 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -523,6 +523,8 @@ const char *safi2str(safi_t safi) return "evpn"; case SAFI_LABELED_UNICAST: return "labeled-unicast"; + case SAFI_FLOWSPEC: + return "flowspec"; default: return "unknown"; } diff --git a/lib/zebra.h b/lib/zebra.h index 3887602231..f4f104299d 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -462,7 +462,8 @@ typedef enum { IANA_SAFI_LABELED_UNICAST = 4, IANA_SAFI_ENCAP = 7, IANA_SAFI_EVPN = 70, - IANA_SAFI_MPLS_VPN = 128 + IANA_SAFI_MPLS_VPN = 128, + IANA_SAFI_FLOWSPEC = 133 } iana_safi_t; /* Default Administrative Distance of each protocol. */ @@ -548,6 +549,8 @@ static inline safi_t safi_iana2int(iana_safi_t safi) return SAFI_EVPN; case IANA_SAFI_LABELED_UNICAST: return SAFI_LABELED_UNICAST; + case IANA_SAFI_FLOWSPEC: + return SAFI_FLOWSPEC; default: return SAFI_MAX; } @@ -568,6 +571,8 @@ static inline iana_safi_t safi_int2iana(safi_t safi) return IANA_SAFI_EVPN; case SAFI_LABELED_UNICAST: return IANA_SAFI_LABELED_UNICAST; + case SAFI_FLOWSPEC: + return IANA_SAFI_FLOWSPEC; default: return IANA_SAFI_RESERVED; } From f77af2c3f2ceb982a8eecb5f5fe743707038a67e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 1 Mar 2018 15:24:39 +0100 Subject: [PATCH 03/14] bgpd: disable aggregation for flowspec entries Flowspec entries do not need aggregation feature. Actually, all flowspec entries are unique. So, some check is done against aggregate functionalities in the code. Signed-off-by: Philippe Guibert --- bgpd/bgp_route.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a37e709f10..aef3ad6a7b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5551,7 +5551,8 @@ void bgp_aggregate_increment(struct bgp *bgp, struct prefix *p, /* MPLS-VPN aggregation is not yet supported. */ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) - || (safi == SAFI_EVPN)) + || (safi == SAFI_EVPN) + || (safi == SAFI_FLOWSPEC)) return; table = bgp->aggregate[afi][safi]; @@ -5589,7 +5590,8 @@ void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p, /* MPLS-VPN aggregation is not yet supported. */ if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) - || (safi == SAFI_EVPN)) + || (safi == SAFI_EVPN) + || (safi == SAFI_FLOWSPEC)) return; table = bgp->aggregate[afi][safi]; @@ -5817,6 +5819,9 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, struct bgp_node *rn; struct bgp_aggregate *aggregate; + if (safi == SAFI_FLOWSPEC) + return CMD_WARNING_CONFIG_FAILED; + /* Convert string to prefix structure. */ ret = str2prefix(prefix_str, &p); if (!ret) { @@ -5860,6 +5865,9 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, struct bgp_node *rn; struct bgp_aggregate *aggregate; + if (safi == SAFI_FLOWSPEC) + return CMD_WARNING_CONFIG_FAILED; + /* Convert string to prefix structure. */ ret = str2prefix(prefix_str, &p); if (!ret) { From 034cdee950eac039382e92ee2a7c8a099c6baabd Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 14 Feb 2018 11:13:50 +0100 Subject: [PATCH 04/14] bgpd: add flowspec utilities to decode, convert fs nlri The FS nlri is depicted so as to be able to be in readable format, either by human, or by some other ( remote daemon ?). This work is a derived work from [0]. Initially done for validation only, this work is extended. The FS NLRI is able to decode addresses, numbers ( protocols, ports, tcp values) combined ( or not) with operators. This makes possible to have a NLRI entry for a set of ports, and/or for an other set of value of port. This implementation mainly brings the API visible. The API should be consistent across the various usages. [0] https://github.com/chinatelecom-sdn-group/quagga_flowspec/ Signed-off-by: Philippe Guibert Signed-off-by: jaydom --- bgpd/Makefile.am | 4 +- bgpd/bgp_flowspec_util.c | 290 +++++++++++++++++++++++++++++++++++++++ bgpd/bgp_flowspec_util.h | 53 +++++++ 3 files changed, 345 insertions(+), 2 deletions(-) create mode 100644 bgpd/bgp_flowspec_util.c create mode 100644 bgpd/bgp_flowspec_util.h diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 84b3e0183c..a8e50e0ba7 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -86,7 +86,7 @@ libbgp_a_SOURCES = \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \ bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c bgp_rd.c \ - bgp_keepalives.c bgp_io.c bgp_flowspec.c + bgp_keepalives.c bgp_io.c bgp_flowspec.c bgp_flowspec_util.c noinst_HEADERS = \ bgp_memory.h \ @@ -99,7 +99,7 @@ noinst_HEADERS = \ bgp_updgrp.h bgp_bfd.h bgp_encap_tlv.h bgp_encap_types.h \ $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \ bgp_vpn.h bgp_label.h bgp_rd.h bgp_evpn_private.h bgp_keepalives.h \ - bgp_io.h bgp_flowspec.h bgp_flowspec_private.h + bgp_io.h bgp_flowspec.h bgp_flowspec_private.h bgp_flowspec_util.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c new file mode 100644 index 0000000000..6b7a3d0063 --- /dev/null +++ b/bgpd/bgp_flowspec_util.c @@ -0,0 +1,290 @@ +/* BGP FlowSpec Utilities + * Portions: + * Copyright (C) 2017 ChinaTelecom SDN Group + * Copyright (C) 2018 6WIND + * + * FRRouting 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. + * + * FRRouting 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 + */ + +#include "zebra.h" + +#include "prefix.h" +#include "bgp_flowspec_util.h" + +static void hex2bin(uint8_t *hex, int *bin) +{ + int remainder = *hex; + int i = 0; + + while (remainder >= 1 && i < 8) { + bin[7-i] = remainder % 2; + remainder = remainder / 2; + i++; + } + for (; i < 8; i++) + bin[7-i] = 0; +} + +static int hexstr2num(uint8_t *hexstr, int len) +{ + int i = 0; + int num = 0; + + for (i = 0; i < len; i++) + num = hexstr[i] + 16*16*num; + return num; +} + + +/* + * handle the flowspec address src/dst or generic address NLRI + * return number of bytes analysed ( >= 0). + */ +int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type, + uint8_t *nlri_ptr, + uint32_t max_len, + void *result, int *error) +{ + char *display = (char *)result; /* for return_string */ + struct prefix *prefix = (struct prefix *)result; + uint32_t offset = 0; + struct prefix prefix_local; + int psize; + + *error = 0; + memset(&prefix_local, 0, sizeof(struct prefix)); + /* read the prefix length */ + prefix_local.prefixlen = nlri_ptr[offset]; + psize = PSIZE(prefix_local.prefixlen); + offset++; + /* TODO Flowspec IPv6 Support */ + prefix_local.family = AF_INET; + /* Prefix length check. */ + if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8) + *error = -1; + /* When packet overflow occur return immediately. */ + if (psize + offset > max_len) + *error = -1; + /* Defensive coding, double-check + * the psize fits in a struct prefix + */ + if (psize > (ssize_t)sizeof(prefix_local.u)) + *error = -1; + memcpy(&prefix_local.u.prefix, &nlri_ptr[offset], psize); + offset += psize; + switch (type) { + case BGP_FLOWSPEC_RETURN_STRING: + prefix2str(&prefix_local, display, + BGP_FLOWSPEC_STRING_DISPLAY_MAX); + break; + case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE: + PREFIX_COPY_IPV4(prefix, &prefix_local) + break; + case BGP_FLOWSPEC_VALIDATE_ONLY: + default: + break; + } + return offset; +} + +/* + * handle the flowspec operator NLRI + * return number of bytes analysed + * if there is an error, the passed error param is used to give error: + * -1 if decoding error, + */ +int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type, + uint8_t *nlri_ptr, + uint32_t max_len, + void *result, int *error) +{ + int op[8]; + int len, value, value_size; + int loop = 0; + char *ptr = (char *)result; /* for return_string */ + uint32_t offset = 0; + + *error = 0; + do { + hex2bin(&nlri_ptr[offset], op); + offset++; + len = 2*op[2]+op[3]; + value_size = 1 << len; + value = hexstr2num(&nlri_ptr[offset], value_size); + /* can not be < and > at the same time */ + if (op[5] == 1 && op[6] == 1) + *error = -1; + /* if first element, AND bit can not be set */ + if (op[1] == 1 && loop == 0) + *error = -1; + switch (type) { + case BGP_FLOWSPEC_RETURN_STRING: + if (loop) + ptr += sprintf(ptr, ", "); + if (op[5] == 1) + ptr += sprintf(ptr, "<"); + if (op[6] == 1) + ptr += sprintf(ptr, ">"); + if (op[7] == 1) + ptr += sprintf(ptr, "="); + ptr += sprintf(ptr, " %d ", value); + break; + case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE: + /* TODO : FS OPAQUE */ + break; + case BGP_FLOWSPEC_VALIDATE_ONLY: + default: + /* no action */ + break; + } + offset += value_size; + loop++; + } while (op[0] == 0 && offset < max_len - 1); + if (offset > max_len) + *error = -1; + /* use error parameter to count the number of entries */ + if (*error == 0) + *error = loop; + return offset; +} + + +/* + * handle the flowspec tcpflags field + * return number of bytes analysed + * if there is an error, the passed error param is used to give error: + * -1 if decoding error, + */ +int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type, + uint8_t *nlri_ptr, + uint32_t max_len, + void *result, int *error) +{ + int op[8]; + int len, value_size, loop = 0, value; + char *ptr = (char *)result; /* for return_string */ + uint32_t offset = 0; + + *error = 0; + do { + hex2bin(&nlri_ptr[offset], op); + /* if first element, AND bit can not be set */ + if (op[1] == 1 && loop == 0) + *error = -1; + offset++; + len = 2 * op[2] + op[3]; + value_size = 1 << len; + value = hexstr2num(&nlri_ptr[offset], value_size); + switch (type) { + case BGP_FLOWSPEC_RETURN_STRING: + if (op[1] == 1 && loop != 0) + ptr += sprintf(ptr, ", and "); + else if (op[1] == 0 && loop != 0) + ptr += sprintf(ptr, ", or "); + ptr += sprintf(ptr, "tcp flags is "); + if (op[6] == 1) + ptr += sprintf(ptr, "not "); + if (op[7] == 1) + ptr += sprintf(ptr, "exactly match "); + ptr += sprintf(ptr, "%d", value); + break; + case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE: + /* TODO : FS OPAQUE */ + break; + case BGP_FLOWSPEC_VALIDATE_ONLY: + default: + /* no action */ + break; + } + offset += value_size; + loop++; + } while (op[0] == 0 && offset < max_len - 1); + if (offset > max_len) + *error = -1; + /* use error parameter to count the number of entries */ + if (*error == 0) + *error = loop; + return offset; +} + +/* + * handle the flowspec fragment type field + * return error (returned values are invalid) or number of bytes analysed + * -1 if error in decoding + * >= 0 : number of bytes analysed (ok). + */ +int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type, + uint8_t *nlri_ptr, + uint32_t max_len, + void *result, int *error) +{ + int op[8]; + int len, value, value_size, loop = 0; + char *ptr = (char *)result; /* for return_string */ + uint32_t offset = 0; + + *error = 0; + do { + hex2bin(&nlri_ptr[offset], op); + offset++; + len = 2 * op[2] + op[3]; + value_size = 1 << len; + value = hexstr2num(&nlri_ptr[offset], value_size); + if (value != 1 && value != 2 && value != 4 && value != 8) + *error = -1; + offset += value_size; + /* TODO : as per RFC5574 : first Fragment bits are Reserved + * does that mean that it is not possible + * to handle multiple occurences ? + * as of today, we only grab the first TCP fragment + */ + if (loop) { + *error = -2; + loop++; + continue; + } + switch (type) { + case BGP_FLOWSPEC_RETURN_STRING: + switch (value) { + case 1: + ptr += sprintf(ptr, "dont-fragment"); + break; + case 2: + ptr += sprintf(ptr, "is-fragment"); + break; + case 4: + ptr += sprintf(ptr, "first-fragment"); + break; + case 8: + ptr += sprintf(ptr, "last-fragment"); + break; + default: + {} + } + break; + case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE: + /* TODO : FS OPAQUE */ + break; + case BGP_FLOWSPEC_VALIDATE_ONLY: + default: + /* no action */ + break; + } + loop++; + } while (op[0] == 0 && offset < max_len - 1); + if (offset > max_len) + *error = -1; + return offset; +} diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h new file mode 100644 index 0000000000..55a464a718 --- /dev/null +++ b/bgpd/bgp_flowspec_util.h @@ -0,0 +1,53 @@ +/* BGP Flowspec header for utilities + * Copyright (C) 2018 6WIND + * + * FRRouting 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. + * + * FRRouting 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 + */ + +#ifndef _FRR_BGP_FLOWSPEC_UTIL_H +#define _FRR_BGP_FLOWSPEC_UTIL_H + +#include "zclient.h" + +#define BGP_FLOWSPEC_STRING_DISPLAY_MAX 512 + +enum bgp_flowspec_util_nlri_t { + BGP_FLOWSPEC_VALIDATE_ONLY = 0, + BGP_FLOWSPEC_RETURN_STRING = 1, + BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE = 2 +}; + + +extern int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type, + uint8_t *nlri_ptr, + uint32_t max_len, + void *result, int *error); + +extern int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type, + uint8_t *nlri_ptr, + uint32_t max_len, + void *result, int *error); + +extern int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type, + uint8_t *nlri_ptr, + uint32_t max_len, + void *result, int *error); + +extern int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type, + uint8_t *nlri_ptr, + uint32_t max_len, + void *result, int *error); + +#endif /* _FRR_BGP_FLOWSPEC_UTIL_H */ From fc83654008749f6d656c9704936d81deb1e6e576 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 1 Mar 2018 16:07:38 +0100 Subject: [PATCH 05/14] bgpd: use bgp flowspec API to validate and receive NLRI The changes introduce validation of NLRI FS entries at incoming, before being pushed in FIB. Note that the so called validation only checks for validity of the incoming flowspec nlri format, and not the validation as per RFC5575. Signed-off-by: Philippe Guibert --- bgpd/bgp_flowspec.c | 92 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index 5d61175dce..ebfa7dae66 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -26,22 +26,84 @@ #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_flowspec.h" +#include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_flowspec_private.h" +static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len) +{ + uint32_t offset = 0; + int type; + int ret = 0, error = 0; + + while (offset < len-1) { + type = nlri_content[offset]; + offset++; + switch (type) { + case FLOWSPEC_DEST_PREFIX: + case FLOWSPEC_SRC_PREFIX: + ret = bgp_flowspec_ip_address( + BGP_FLOWSPEC_VALIDATE_ONLY, + nlri_content + offset, + len - offset, NULL, &error); + break; + case FLOWSPEC_IP_PROTOCOL: + case FLOWSPEC_PORT: + case FLOWSPEC_DEST_PORT: + case FLOWSPEC_SRC_PORT: + case FLOWSPEC_ICMP_TYPE: + case FLOWSPEC_ICMP_CODE: + ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY, + nlri_content + offset, + len - offset, NULL, &error); + break; + case FLOWSPEC_TCP_FLAGS: + ret = bgp_flowspec_tcpflags_decode( + BGP_FLOWSPEC_VALIDATE_ONLY, + nlri_content + offset, + len - offset, NULL, &error); + break; + case FLOWSPEC_PKT_LEN: + case FLOWSPEC_DSCP: + ret = bgp_flowspec_op_decode( + BGP_FLOWSPEC_VALIDATE_ONLY, + nlri_content + offset, + len - offset, NULL, &error); + break; + case FLOWSPEC_FRAGMENT: + ret = bgp_flowspec_fragment_type_decode( + BGP_FLOWSPEC_VALIDATE_ONLY, + nlri_content + offset, + len - offset, NULL, &error); + break; + default: + error = -1; + break; + } + offset += ret; + if (error < 0) + break; + } + return error; +} + int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, struct bgp_nlri *packet, int withdraw) { uint8_t *pnt; uint8_t *lim; afi_t afi; + safi_t safi; int psize = 0; uint8_t rlen; struct prefix p; + int ret; + void *temp; /* Start processing the NLRI - there may be multiple in the MP_REACH */ pnt = packet->nlri; lim = pnt + packet->length; afi = packet->afi; + safi = packet->safi; if (afi == AFI_IP6) { zlog_err("BGP flowspec IPv6 not supported"); @@ -70,9 +132,33 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, psize); return -1; } - /* TODO: validate prefix - * and add to FIB - */ + if (bgp_fs_nlri_validate(pnt, psize) < 0) { + zlog_err("Bad flowspec format or NLRI options not supported"); + return -1; + } + p.family = AF_FLOWSPEC; + p.prefixlen = 0; + /* Flowspec encoding is in bytes */ + p.u.prefix_flowspec.prefixlen = psize; + temp = XCALLOC(MTYPE_TMP, psize); + memcpy(temp, pnt, psize); + p.u.prefix_flowspec.ptr = (uintptr_t) temp; + /* Process the route. */ + if (!withdraw) + ret = bgp_update(peer, &p, 0, attr, + afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + NULL, NULL, 0, 0, NULL); + else + ret = bgp_withdraw(peer, &p, 0, attr, + afi, safi, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + NULL, NULL, 0, NULL); + if (ret) { + zlog_err("Flowspec NLRI failed to be %s.", + attr ? "added" : "withdrawn"); + return -1; + } } return 0; } From a8d72b61eb87cf0aea03d4075247eb5290666c8d Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 15 Jan 2018 19:17:02 +0100 Subject: [PATCH 06/14] bgpd: ecommunity show bgp ipv4 flowspec ecommunity library is modified to return the flowspec ecommunities in display format. Signed-off-by: Philippe Guibert --- bgpd/bgp_ecommunity.c | 66 ++++++++++++++++++++++++++++++++++++- bgpd/bgp_ecommunity.h | 9 +++++ bgpd/bgp_flowspec_private.h | 5 +++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 8b60ead383..54ec7d392b 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -33,6 +33,13 @@ #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_flowspec_private.h" + +/* struct used to dump the rate contained in FS set traffic-rate EC */ +union traffic_rate { + float rate_float; + uint8_t rate_byte[4]; +}; /* Hash of community attribute. */ static struct hash *ecomhash; @@ -661,8 +668,10 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) } /* Space between each value. */ - if (!first) + if (!first) { str_buf[str_pnt++] = ' '; + len++; + } pnt = ecom->val + (i * 8); @@ -727,6 +736,61 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) "MM:%u", seqnum); } else unk_ecom = 1; + } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP) { + sub_type = *pnt++; + + if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) { + char action[64]; + char *ptr = action; + + if (*(pnt+3) == + 1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL) + ptr += snprintf(ptr, sizeof(action), + "terminate (apply)"); + else + ptr += snprintf(ptr, sizeof(action), + "eval stops"); + if (*(pnt+3) == + 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE) + snprintf(ptr, sizeof(action) - + (size_t)(ptr-action), + ", sample"); + len = snprintf(str_buf + str_pnt, + str_size - len, + "FS:action %s", action); + } else if (sub_type == ECOMMUNITY_TRAFFIC_RATE) { + union traffic_rate data; + + data.rate_byte[3] = *(pnt+2); + data.rate_byte[2] = *(pnt+3); + data.rate_byte[1] = *(pnt+4); + data.rate_byte[0] = *(pnt+5); + len = sprintf( + str_buf + str_pnt, + "FS:rate %f", data.rate_float); + } else if (sub_type == ECOMMUNITY_REDIRECT_VRF) { + char buf[16]; + + memset(buf, 0, sizeof(buf)); + ecommunity_rt_soo_str(buf, (uint8_t *)pnt, + type & + ~ECOMMUNITY_ENCODE_TRANS_EXP, + ECOMMUNITY_ROUTE_TARGET, + ECOMMUNITY_FORMAT_DISPLAY); + len = snprintf( + str_buf + str_pnt, + str_size - len, + "FS:redirect VRF %s", buf); + } else if (sub_type == ECOMMUNITY_TRAFFIC_MARKING) { + len = sprintf( + str_buf + str_pnt, + "FS:marking %u", *(pnt+5)); + } else if (sub_type == ECOMMUNITY_REDIRECT_IP_NH) { + len = sprintf( + str_buf + str_pnt, + "FS:redirect IP 0x%x", *(pnt+5)); + } else + unk_ecom = 1; } else unk_ecom = 1; diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 028b7a3166..31ff1481ba 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -27,10 +27,19 @@ #define ECOMMUNITY_ENCODE_AS4 0x02 #define ECOMMUNITY_ENCODE_OPAQUE 0x03 #define ECOMMUNITY_ENCODE_EVPN 0x06 +#define ECOMMUNITY_ENCODE_TRANS_EXP 0x80 /* Flow Spec */ +/* RFC7674 */ +#define ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 0x81 +#define ECOMMUNITY_EXTENDED_COMMUNITY_PART_3 0x82 /* Low-order octet of the Extended Communities type field. */ #define ECOMMUNITY_ROUTE_TARGET 0x02 #define ECOMMUNITY_SITE_ORIGIN 0x03 +#define ECOMMUNITY_TRAFFIC_RATE 0x06 /* Flow Spec */ +#define ECOMMUNITY_TRAFFIC_ACTION 0x07 +#define ECOMMUNITY_REDIRECT_VRF 0x08 +#define ECOMMUNITY_TRAFFIC_MARKING 0x09 +#define ECOMMUNITY_REDIRECT_IP_NH 0x00 /* Low-order octet of the Extended Communities type field for EVPN types */ #define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00 diff --git a/bgpd/bgp_flowspec_private.h b/bgpd/bgp_flowspec_private.h index c82bb78519..4f086a9f7b 100644 --- a/bgpd/bgp_flowspec_private.h +++ b/bgpd/bgp_flowspec_private.h @@ -21,4 +21,9 @@ #define FLOWSPEC_NLRI_SIZELIMIT 240 +/* Flowspec raffic action bit*/ +#define FLOWSPEC_TRAFFIC_ACTION_TERMINAL 1 +#define FLOWSPEC_TRAFFIC_ACTION_SAMPLE 0 +#define FLOWSPEC_TRAFFIC_ACTION_DISTRIBUTE 1 + #endif /* _FRR_BGP_FLOWSPEC_PRIVATE_H */ From dba3c1d3fbf563aab505aebeed0ece7480e895a4 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 19 Feb 2018 17:17:41 +0100 Subject: [PATCH 07/14] bgpd: support for show bgp ipv4 flowspec The show bgp ipv4 flowspec routine is made available, displays the flowspec rules contained in the BGP FIB database, as well as the actions to be done on those rules. Two routines are available: show bgp ipv4 flowspec show bgp ipv4 flowspec detail Signed-off-by: Philippe Guibert --- bgpd/Makefile.am | 3 +- bgpd/bgp_flowspec.h | 20 +++ bgpd/bgp_flowspec_private.h | 15 ++ bgpd/bgp_flowspec_vty.c | 276 ++++++++++++++++++++++++++++++++++++ bgpd/bgp_route.c | 40 ++++++ bgpd/bgp_route.h | 3 +- 6 files changed, 355 insertions(+), 2 deletions(-) create mode 100644 bgpd/bgp_flowspec_vty.c diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index a8e50e0ba7..61d46dfcb9 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -86,7 +86,8 @@ libbgp_a_SOURCES = \ bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \ bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \ bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c bgp_rd.c \ - bgp_keepalives.c bgp_io.c bgp_flowspec.c bgp_flowspec_util.c + bgp_keepalives.c bgp_io.c bgp_flowspec.c bgp_flowspec_util.c \ + bgp_flowspec_vty.c noinst_HEADERS = \ bgp_memory.h \ diff --git a/bgpd/bgp_flowspec.h b/bgpd/bgp_flowspec.h index bf019da3aa..791ed2e693 100644 --- a/bgpd/bgp_flowspec.h +++ b/bgpd/bgp_flowspec.h @@ -19,9 +19,29 @@ #ifndef _FRR_BGP_FLOWSPEC_H #define _FRR_BGP_FLOWSPEC_H +#define NLRI_STRING_FORMAT_LARGE 0 +#define NLRI_STRING_FORMAT_DEBUG 1 +#define NLRI_STRING_FORMAT_MIN 2 + +#define BGP_FLOWSPEC_NLRI_STRING_MAX 512 + extern int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, struct bgp_nlri *packet, int withdraw); extern void bgp_flowspec_vty_init(void); +extern int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, + struct bgp_table *table, + enum bgp_show_type type, + void *output_arg, uint8_t use_json, + int is_last, + unsigned long *output_cum, + unsigned long *total_cum); + +extern void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, + char *return_string, int format); + +extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p, + struct bgp_info *binfo, + int display, json_object *json_paths); #endif /* _FRR_BGP_FLOWSPEC_H */ diff --git a/bgpd/bgp_flowspec_private.h b/bgpd/bgp_flowspec_private.h index 4f086a9f7b..dede4e03d3 100644 --- a/bgpd/bgp_flowspec_private.h +++ b/bgpd/bgp_flowspec_private.h @@ -26,4 +26,19 @@ #define FLOWSPEC_TRAFFIC_ACTION_SAMPLE 0 #define FLOWSPEC_TRAFFIC_ACTION_DISTRIBUTE 1 +/* Flow Spec Component Types */ +#define NUM_OF_FLOWSPEC_MATCH_TYPES 12 +#define FLOWSPEC_DEST_PREFIX 1 +#define FLOWSPEC_SRC_PREFIX 2 +#define FLOWSPEC_IP_PROTOCOL 3 +#define FLOWSPEC_PORT 4 +#define FLOWSPEC_DEST_PORT 5 +#define FLOWSPEC_SRC_PORT 6 +#define FLOWSPEC_ICMP_TYPE 7 +#define FLOWSPEC_ICMP_CODE 8 +#define FLOWSPEC_TCP_FLAGS 9 +#define FLOWSPEC_PKT_LEN 10 +#define FLOWSPEC_DSCP 11 +#define FLOWSPEC_FRAGMENT 12 + #endif /* _FRR_BGP_FLOWSPEC_PRIVATE_H */ diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c new file mode 100644 index 0000000000..1006022683 --- /dev/null +++ b/bgpd/bgp_flowspec_vty.c @@ -0,0 +1,276 @@ +/* BGP FlowSpec VTY + * Copyright (C) 2018 6WIND + * + * FRRouting 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. + * + * FRRouting 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 + */ + +#include +#include "command.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_table.h" +#include "bgpd/bgp_attr.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_vty.h" +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_aspath.h" +#include "bgpd/bgp_flowspec.h" +#include "bgpd/bgp_flowspec_util.h" +#include "bgpd/bgp_flowspec_private.h" + +/* Local Structures and variables declarations + * This code block hosts the struct declared that host the flowspec rules + * as well as some structure used to convert to stringx + */ + +static const struct message bgp_flowspec_display_large[] = { + {FLOWSPEC_DEST_PREFIX, "Destination Address"}, + {FLOWSPEC_SRC_PREFIX, "Source Address"}, + {FLOWSPEC_IP_PROTOCOL, "IP Protocol"}, + {FLOWSPEC_PORT, "Port"}, + {FLOWSPEC_DEST_PORT, "Destination Port"}, + {FLOWSPEC_SRC_PORT, "Source Port"}, + {FLOWSPEC_ICMP_TYPE, "ICMP Type"}, + {FLOWSPEC_ICMP_CODE, "ICMP Code"}, + {FLOWSPEC_TCP_FLAGS, "TCP Flags"}, + {FLOWSPEC_PKT_LEN, "Packet Length"}, + {FLOWSPEC_DSCP, "DSCP field"}, + {FLOWSPEC_FRAGMENT, "Packet Fragment"}, + {0} +}; + +static const struct message bgp_flowspec_display_min[] = { + {FLOWSPEC_DEST_PREFIX, "to"}, + {FLOWSPEC_SRC_PREFIX, "from"}, + {FLOWSPEC_IP_PROTOCOL, "proto"}, + {FLOWSPEC_PORT, "port"}, + {FLOWSPEC_DEST_PORT, "dstp"}, + {FLOWSPEC_SRC_PORT, "srcp"}, + {FLOWSPEC_ICMP_TYPE, "type"}, + {FLOWSPEC_ICMP_CODE, "code"}, + {FLOWSPEC_TCP_FLAGS, "flags"}, + {FLOWSPEC_PKT_LEN, "pktlen"}, + {FLOWSPEC_DSCP, "dscp"}, + {FLOWSPEC_FRAGMENT, "pktfrag"}, + {0} +}; + +#define FS_STRING_UPDATE(count, ptr, format) do { \ + if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) { \ + (ptr) += sprintf((ptr), ", "); \ + } else if (((format) == NLRI_STRING_FORMAT_MIN) && (count)) { \ + (ptr) += sprintf((ptr), " "); \ + } \ + count++; \ + } while (0) + +/* Parse FLOWSPEC NLRI*/ +void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, + char *return_string, int format) +{ + uint32_t offset = 0; + int type; + int ret = 0, error = 0; + char *ptr = return_string; + char local_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX]; + int count = 0; + char extra[2] = ""; + char pre_extra[2] = ""; + const struct message *bgp_flowspec_display; + + if (format == NLRI_STRING_FORMAT_LARGE) { + snprintf(pre_extra, sizeof(pre_extra), "\t"); + snprintf(extra, sizeof(extra), "\n"); + bgp_flowspec_display = bgp_flowspec_display_large; + } else + bgp_flowspec_display = bgp_flowspec_display_min; + error = 0; + while (offset < len-1 && error >= 0) { + type = nlri_content[offset]; + offset++; + switch (type) { + case FLOWSPEC_DEST_PREFIX: + case FLOWSPEC_SRC_PREFIX: + ret = bgp_flowspec_ip_address( + BGP_FLOWSPEC_RETURN_STRING, + nlri_content+offset, + len - offset, + local_string, &error); + if (ret <= 0) + break; + FS_STRING_UPDATE(count, ptr, format); + ptr += sprintf(ptr, "%s%s %s%s", pre_extra, + lookup_msg(bgp_flowspec_display, type, ""), + local_string, extra); + break; + case FLOWSPEC_IP_PROTOCOL: + case FLOWSPEC_PORT: + case FLOWSPEC_DEST_PORT: + case FLOWSPEC_SRC_PORT: + case FLOWSPEC_ICMP_TYPE: + case FLOWSPEC_ICMP_CODE: + ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_RETURN_STRING, + nlri_content+offset, + len - offset, + local_string, &error); + if (ret <= 0) + break; + FS_STRING_UPDATE(count, ptr, format); + ptr += sprintf(ptr, "%s%s %s%s", pre_extra, + lookup_msg(bgp_flowspec_display, + type, ""), + local_string, extra); + break; + case FLOWSPEC_TCP_FLAGS: + ret = bgp_flowspec_tcpflags_decode( + BGP_FLOWSPEC_RETURN_STRING, + nlri_content+offset, + len - offset, + local_string, &error); + if (ret <= 0) + break; + FS_STRING_UPDATE(count, ptr, format); + ptr += sprintf(ptr, "%s%s %s%s", pre_extra, + lookup_msg(bgp_flowspec_display, type, ""), + local_string, extra); + break; + case FLOWSPEC_PKT_LEN: + case FLOWSPEC_DSCP: + ret = bgp_flowspec_op_decode( + BGP_FLOWSPEC_RETURN_STRING, + nlri_content + offset, + len - offset, local_string, + &error); + if (ret <= 0) + break; + FS_STRING_UPDATE(count, ptr, format); + ptr += sprintf(ptr, "%s%s %s%s", pre_extra, + lookup_msg(bgp_flowspec_display, + type, ""), + local_string, extra); + break; + case FLOWSPEC_FRAGMENT: + ret = bgp_flowspec_fragment_type_decode( + BGP_FLOWSPEC_RETURN_STRING, + nlri_content + offset, + len - offset, local_string, + &error); + if (ret <= 0) + break; + FS_STRING_UPDATE(count, ptr, format); + ptr += sprintf(ptr, "%s%s %s%s", pre_extra, + lookup_msg(bgp_flowspec_display, + type, ""), + local_string, extra); + break; + default: + error = -1; + break; + } + offset += ret; + } +} + +void route_vty_out_flowspec(struct vty *vty, struct prefix *p, + struct bgp_info *binfo, + int display, json_object *json_paths) +{ + struct attr *attr; + char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX]; + char *s; + + /* Print prefix */ + if (p != NULL) { + if (p->family != AF_FLOWSPEC) + return; + if (display == NLRI_STRING_FORMAT_LARGE) + vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n", + binfo->flags); + bgp_fs_nlri_get_string((unsigned char *) + p->u.prefix_flowspec.ptr, + p->u.prefix_flowspec.prefixlen, + return_string, + display); + if (display == NLRI_STRING_FORMAT_LARGE) + vty_out(vty, "%s", return_string); + else if (display == NLRI_STRING_FORMAT_DEBUG) + vty_out(vty, "%s", return_string); + else + vty_out(vty, " %-30s", return_string); + } + if (!binfo) + return; + if (binfo->attr && binfo->attr->ecommunity) { + /* Print attribute */ + attr = binfo->attr; + s = ecommunity_ecom2str(attr->ecommunity, + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + if (!s) + return; + if (display == NLRI_STRING_FORMAT_LARGE) + vty_out(vty, "\t%s\n", s); + else + vty_out(vty, "%s", s); + XFREE(MTYPE_ECOMMUNITY_STR, s); + } + if (display == NLRI_STRING_FORMAT_LARGE) { + char timebuf[BGP_UPTIME_LEN]; + + vty_out(vty, "\tup for %8s\n", + peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN, + 0, NULL)); + } + +} + +int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, + struct bgp_table *table, enum bgp_show_type type, + void *output_arg, uint8_t use_json, + int is_last, unsigned long *output_cum, + unsigned long *total_cum) +{ + struct bgp_info *ri; + struct bgp_node *rn; + unsigned long total_count = 0; + json_object *json_paths = NULL; + int display; + + if (type != bgp_show_type_detail) + return CMD_SUCCESS; + + display = NLRI_STRING_FORMAT_LARGE; + if (use_json) /* XXX */ + return CMD_SUCCESS; + for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { + if (rn->info == NULL) + continue; + for (ri = rn->info; ri; ri = ri->next) { + total_count++; + route_vty_out_flowspec(vty, &rn->p, + ri, display, + json_paths); + + } + } + if (total_count) + vty_out(vty, + "\nDisplayed %ld flowspec entries\n", + total_count); + return CMD_SUCCESS; +} + +void bgp_flowspec_vty_init(void) +{ +} diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index aef3ad6a7b..db82386e72 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -73,6 +73,7 @@ #include "bgpd/bgp_encap_tlv.h" #include "bgpd/bgp_evpn.h" #include "bgpd/bgp_evpn_vty.h" +#include "bgpd/bgp_flowspec.h" #ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_route_clippy.c" @@ -6316,6 +6317,9 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty, prefix2str(p, buf, PREFIX_STRLEN); len = vty_out(vty, "%s", buf); #endif + } else if (p->family == AF_FLOWSPEC) { + route_vty_out_flowspec(vty, p, NULL, + NLRI_STRING_FORMAT_MIN, json); } else { if (!json) len = vty_out( @@ -8429,6 +8433,12 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, return bgp_show_table_rd(vty, bgp, safi, table, NULL, type, output_arg, use_json); } + + if (safi == SAFI_FLOWSPEC && type == bgp_show_type_detail) { + return bgp_show_table_flowspec(vty, bgp, afi, table, type, + output_arg, use_json, + 1, NULL, NULL); + } /* labeled-unicast routes live in the unicast table */ else if (safi == SAFI_LABELED_UNICAST) safi = SAFI_UNICAST; @@ -10425,6 +10435,32 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer, return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, use_json); } +DEFUN (show_ip_bgp_flowspec_routes_detailed, + show_ip_bgp_flowspec_routes_detailed_cmd, + "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" flowspec] detail [json]", + SHOW_STR + IP_STR + BGP_STR + BGP_INSTANCE_HELP_STR + BGP_AFI_HELP_STR + "SAFI Flowspec\n" + "Detailed information on flowspec entries\n" + JSON_STR) +{ + afi_t afi = AFI_IP; + safi_t safi = SAFI_UNICAST; + struct bgp *bgp = NULL; + int idx = 0; + + bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, + &bgp); + if (!idx) + return CMD_WARNING; + + return bgp_show(vty, bgp, afi, safi, + bgp_show_type_detail, NULL, use_json(argc, argv)); +} + DEFUN (show_ip_bgp_neighbor_routes, show_ip_bgp_neighbor_routes_cmd, "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] " @@ -11439,6 +11475,10 @@ void bgp_route_init(void) /* Large Communities */ install_element(VIEW_NODE, &show_ip_bgp_large_community_list_cmd); install_element(VIEW_NODE, &show_ip_bgp_large_community_cmd); + + /* show bgp ipv4 flowspec detailed */ + install_element(VIEW_NODE, &show_ip_bgp_flowspec_routes_detailed_cmd); + } void bgp_route_finish(void) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e1e43bbde3..debd6d1ff3 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -48,7 +48,8 @@ enum bgp_show_type { bgp_show_type_flap_statistics, bgp_show_type_flap_neighbor, bgp_show_type_dampend_paths, - bgp_show_type_damp_neighbor + bgp_show_type_damp_neighbor, + bgp_show_type_detail, }; From 268e1b9b924ed1068bcdf1a5e49ce830f4cc7914 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 20 Feb 2018 10:58:42 +0100 Subject: [PATCH 08/14] bgpd: introduce [no] debug bgp flowspec It is possible to enhance debug bgp flowspec feature by using vty command. This command, if enabled, will dump the match/set couple of information received on NLRI. Signed-off-by: Philippe Guibert --- bgpd/bgp_debug.c | 24 +++++++++++++++++++++++- bgpd/bgp_debug.h | 3 +++ bgpd/bgp_flowspec.c | 31 +++++++++++++++++++++++++++++++ bgpd/bgp_flowspec_vty.c | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 54fcd47e4b..8801028313 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -42,6 +42,7 @@ #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_label.h" #include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_flowspec.h" unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_neighbor_events; @@ -56,6 +57,7 @@ unsigned long conf_bgp_debug_allow_martians; unsigned long conf_bgp_debug_nht; unsigned long conf_bgp_debug_update_groups; unsigned long conf_bgp_debug_vpn; +unsigned long conf_bgp_debug_flowspec; unsigned long term_bgp_debug_as4; unsigned long term_bgp_debug_neighbor_events; @@ -70,6 +72,7 @@ unsigned long term_bgp_debug_allow_martians; unsigned long term_bgp_debug_nht; unsigned long term_bgp_debug_update_groups; unsigned long term_bgp_debug_vpn; +unsigned long term_bgp_debug_flowspec; struct list *bgp_debug_neighbor_events_peers = NULL; struct list *bgp_debug_keepalive_peers = NULL; @@ -1688,6 +1691,7 @@ DEFUN (no_debug_bgp, TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF); TERM_DEBUG_OFF(vpn, VPN_LEAK_RMAP_EVENT); TERM_DEBUG_OFF(vpn, VPN_LEAK_LABEL); + TERM_DEBUG_OFF(flowspec, FLOWSPEC); vty_out(vty, "All possible debugging has been turned off\n"); return CMD_SUCCESS; @@ -1758,6 +1762,8 @@ DEFUN_NOSH (show_debugging_bgp, vty_out(vty, " BGP vpn route-map event debugging is on\n"); if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) vty_out(vty, " BGP vpn label event debugging is on\n"); + if (BGP_DEBUG(flowspec, FLOWSPEC)) + vty_out(vty, " BGP flowspec debugging is on\n"); vty_out(vty, "\n"); return CMD_SUCCESS; @@ -1811,6 +1817,8 @@ int bgp_debug_count(void) ret++; if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) ret++; + if (BGP_DEBUG(flowspec, FLOWSPEC)) + ret++; return ret; } @@ -1904,6 +1912,10 @@ static int bgp_config_write_debug(struct vty *vty) vty_out(vty, "debug bgp vpn label\n"); write++; } + if (CONF_BGP_DEBUG(flowspec, FLOWSPEC)) { + vty_out(vty, "debug bgp flowspec\n"); + write++; + } return write; } @@ -2204,7 +2216,17 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, prefix_rd2str(prd, rd_buf, sizeof(rd_buf)), prefix2str(pu, pfx_buf, sizeof(pfx_buf)), tag_buf, pathid_buf, afi2str(afi), safi2str(safi)); - else + else if (safi == SAFI_FLOWSPEC) { + char return_string[BGP_FLOWSPEC_NLRI_STRING_MAX]; + const struct prefix_fs *fs = pu.fs; + + bgp_fs_nlri_get_string((unsigned char *)fs->prefix.ptr, + fs->prefix.prefixlen, + return_string, + NLRI_STRING_FORMAT_DEBUG); + snprintf(str, size, "FS %s Match{%s}", afi2str(afi), + return_string); + } else snprintf(str, size, "%s%s%s %s %s", prefix2str(pu, pfx_buf, sizeof(pfx_buf)), tag_buf, pathid_buf, afi2str(afi), safi2str(safi)); diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index d5dee59910..a0b179e213 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -73,6 +73,7 @@ extern unsigned long conf_bgp_debug_allow_martians; extern unsigned long conf_bgp_debug_nht; extern unsigned long conf_bgp_debug_update_groups; extern unsigned long conf_bgp_debug_vpn; +extern unsigned long conf_bgp_debug_flowspec; extern unsigned long term_bgp_debug_as4; extern unsigned long term_bgp_debug_neighbor_events; @@ -85,6 +86,7 @@ extern unsigned long term_bgp_debug_allow_martians; extern unsigned long term_bgp_debug_nht; extern unsigned long term_bgp_debug_update_groups; extern unsigned long term_bgp_debug_vpn; +extern unsigned long term_bgp_debug_flowspec; extern struct list *bgp_debug_neighbor_events_peers; extern struct list *bgp_debug_keepalive_peers; @@ -117,6 +119,7 @@ struct bgp_debug_filter { #define BGP_DEBUG_VPN_LEAK_TO_VRF 0x02 #define BGP_DEBUG_VPN_LEAK_RMAP_EVENT 0x04 #define BGP_DEBUG_VPN_LEAK_LABEL 0x08 +#define BGP_DEBUG_FLOWSPEC 0x01 #define BGP_DEBUG_PACKET_SEND 0x01 #define BGP_DEBUG_PACKET_SEND_DETAIL 0x02 diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index ebfa7dae66..d53271e851 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -28,6 +28,8 @@ #include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_flowspec_private.h" +#include "bgpd/bgp_ecommunity.h" +#include "bgpd/bgp_debug.h" static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len) { @@ -143,6 +145,35 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, temp = XCALLOC(MTYPE_TMP, psize); memcpy(temp, pnt, psize); p.u.prefix_flowspec.ptr = (uintptr_t) temp; + + if (BGP_DEBUG(flowspec, FLOWSPEC)) { + char return_string[BGP_FLOWSPEC_NLRI_STRING_MAX]; + char local_string[BGP_FLOWSPEC_NLRI_STRING_MAX]; + char ec_string[BGP_FLOWSPEC_NLRI_STRING_MAX]; + char *s = NULL; + + bgp_fs_nlri_get_string((unsigned char *) + p.u.prefix_flowspec.ptr, + p.u.prefix_flowspec.prefixlen, + return_string, + NLRI_STRING_FORMAT_MIN); + snprintf(ec_string, BGP_FLOWSPEC_NLRI_STRING_MAX, + "EC{none}"); + if (attr && attr->ecommunity) { + s = ecommunity_ecom2str(attr->ecommunity, + ECOMMUNITY_FORMAT_ROUTE_MAP, 0); + snprintf(ec_string, + BGP_FLOWSPEC_NLRI_STRING_MAX, + "EC{%s}", + s == NULL ? "none" : s); + } + snprintf(local_string, BGP_FLOWSPEC_NLRI_STRING_MAX, + "FS Rx %s %s %s %s", withdraw ? + "Withdraw":"Update", + afi2str(afi), return_string, + attr != NULL ? ec_string : ""); + zlog_info("%s", local_string); + } /* Process the route. */ if (!withdraw) ret = bgp_update(peer, &p, 0, attr, diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 1006022683..76ac0888b4 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -29,6 +29,7 @@ #include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_flowspec_private.h" +#include "bgpd/bgp_debug.h" /* Local Structures and variables declarations * This code block hosts the struct declared that host the flowspec rules @@ -271,6 +272,43 @@ int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, return CMD_SUCCESS; } +DEFUN (debug_bgp_flowspec, + debug_bgp_flowspec_cmd, + "debug bgp flowspec", + DEBUG_STR + BGP_STR + "BGP allow flowspec debugging entries\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_ON(flowspec, FLOWSPEC); + else { + TERM_DEBUG_ON(flowspec, FLOWSPEC); + vty_out(vty, "BGP flowspec debugging is on\n"); + } + return CMD_SUCCESS; +} + +DEFUN (no_debug_bgp_flowspec, + no_debug_bgp_flowspec_cmd, + "no debug bgp flowspec", + NO_STR + DEBUG_STR + BGP_STR + "BGP allow flowspec debugging entries\n") +{ + if (vty->node == CONFIG_NODE) + DEBUG_OFF(flowspec, FLOWSPEC); + else { + TERM_DEBUG_OFF(flowspec, FLOWSPEC); + vty_out(vty, "BGP flowspec debugging is off\n"); + } + return CMD_SUCCESS; +} + void bgp_flowspec_vty_init(void) { + install_element(ENABLE_NODE, &debug_bgp_flowspec_cmd); + install_element(CONFIG_NODE, &debug_bgp_flowspec_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_flowspec_cmd); } From 3bc593a8f79375247f80eca0be2904197ae949f3 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 6 Mar 2018 14:25:48 +0100 Subject: [PATCH 09/14] tests: add flowspec test with BGP MP_REACH/UNREACH This commit checks that the reception of MP_REACH and MP_UNREACH flowspec is handled correctly. Signed-off-by: Philippe Guibert --- tests/bgpd/test_mp_attr.c | 41 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index fff1652473..34c35cfcc5 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -809,7 +809,26 @@ static struct test_segment { 37, SHOULD_ERR, }, - + { + .name = "IPv4", + .desc = "IPV4 MP Reach, flowspec, 1 NLRI", + .data = { + /* AFI / SAFI */ 0x0, + AFI_IP, + IANA_SAFI_FLOWSPEC, + 0x00, /* no NH */ + 0x00, + 0x06, /* FS Length */ + 0x01, /* FS dest prefix ID */ + 0x1e, /* IP */ + 0x1e, + 0x28, + 0x28, + 0x0 + }, + .len = 12, + .parses = SHOULD_PARSE, + }, {NULL, NULL, {0}, 0, 0}}; /* MP_UNREACH_NLRI tests */ @@ -906,6 +925,24 @@ static struct test_segment mp_unreach_segments[] = { (3 + (1 + 3 + 8 + 2) + (1 + 3 + 8 + 3)), SHOULD_PARSE, }, + { + .name = "IPv4", + .desc = "IPV4 MP Unreach, flowspec, 1 NLRI", + .data = { + /* AFI / SAFI */ 0x0, + AFI_IP, + IANA_SAFI_FLOWSPEC, + 0x06, /* FS Length */ + 0x01, /* FS dest prefix ID */ + 0x1e, /* IP */ + 0x1e, + 0x28, + 0x28, + 0x0 + }, + .len = 10, + .parses = SHOULD_PARSE, + }, {NULL, NULL, {0}, 0, 0}}; /* nlri_parse indicates 0 on successful parse, and -1 otherwise. @@ -1002,9 +1039,11 @@ int main(void) conf_bgp_debug_neighbor_events = -1UL; conf_bgp_debug_packet = -1UL; conf_bgp_debug_as4 = -1UL; + conf_bgp_debug_flowspec = -1UL; term_bgp_debug_neighbor_events = -1UL; term_bgp_debug_packet = -1UL; term_bgp_debug_as4 = -1UL; + term_bgp_debug_flowspec = -1UL; qobj_init(); cmd_init(0); From e7d78d0f2ceab5d0c078961d0377265ddecf5e43 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 7 Mar 2018 10:02:45 +0100 Subject: [PATCH 10/14] vtysh: add flowspec address family cmd support add flowspec v4 and flowspec v6 address family support for BGP. Signed-off-by: Philippe Guibert --- vtysh/vtysh.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 96a5ea9e36..1e114d1ce0 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -339,6 +339,8 @@ static int vtysh_execute_func(const char *line, int pager) || saved_node == BGP_VPNV6_NODE || saved_node == BGP_IPV4_NODE || saved_node == BGP_IPV6_NODE + || saved_node == BGP_FLOWSPECV4_NODE + || saved_node == BGP_FLOWSPECV6_NODE || saved_node == BGP_IPV4M_NODE || saved_node == BGP_IPV4L_NODE || saved_node == BGP_IPV6L_NODE @@ -622,6 +624,8 @@ int vtysh_mark_file(const char *filename) || prev_node == BGP_VPNV6_NODE || prev_node == BGP_IPV4_NODE || prev_node == BGP_IPV6_NODE + || prev_node == BGP_FLOWSPECV4_NODE + || prev_node == BGP_FLOWSPECV6_NODE || prev_node == BGP_IPV4L_NODE || prev_node == BGP_IPV6L_NODE || prev_node == BGP_IPV4M_NODE @@ -992,6 +996,12 @@ static struct cmd_node bgp_vpnv4_node = {BGP_VPNV4_NODE, static struct cmd_node bgp_vpnv6_node = {BGP_VPNV6_NODE, "%s(config-router-af)# "}; +static struct cmd_node bgp_flowspecv4_node = {BGP_FLOWSPECV4_NODE, + "%s(config-router-af)# "}; + +static struct cmd_node bgp_flowspecv6_node = {BGP_FLOWSPECV6_NODE, + "%s(config-router-af)# "}; + static struct cmd_node bgp_ipv4_node = {BGP_IPV4_NODE, "%s(config-router-af)# "}; @@ -1132,6 +1142,26 @@ DEFUNSH(VTYSH_BGPD, address_family_ipv4, address_family_ipv4_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_BGPD, address_family_flowspecv4, address_family_flowspecv4_cmd, + "address-family ipv4 flowspec", + "Enter Address Family command mode\n" + "Address Family\n" + "Address Family Modifier\n") +{ + vty->node = BGP_FLOWSPECV4_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_BGPD, address_family_flowspecv6, address_family_flowspecv6_cmd, + "address-family ipv6 flowspec", + "Enter Address Family command mode\n" + "Address Family\n" + "Address Family Modifier\n") +{ + vty->node = BGP_FLOWSPECV6_NODE; + return CMD_SUCCESS; +} + DEFUNSH(VTYSH_BGPD, address_family_ipv4_multicast, address_family_ipv4_multicast_cmd, "address-family ipv4 multicast", "Enter Address Family command mode\n" @@ -1537,6 +1567,8 @@ static int vtysh_exit(struct vty *vty) case BGP_IPV6_NODE: case BGP_IPV6M_NODE: case BGP_IPV6L_NODE: + case BGP_FLOWSPECV4_NODE: + case BGP_FLOWSPECV6_NODE: case BGP_VRF_POLICY_NODE: case BGP_EVPN_NODE: case BGP_VNC_DEFAULTS_NODE: @@ -1591,7 +1623,9 @@ DEFUNSH(VTYSH_BGPD, exit_address_family, exit_address_family_cmd, || vty->node == BGP_IPV4L_NODE || vty->node == BGP_VPNV4_NODE || vty->node == BGP_VPNV6_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6L_NODE || vty->node == BGP_IPV6M_NODE - || vty->node == BGP_EVPN_NODE) + || vty->node == BGP_EVPN_NODE + || vty->node == BGP_FLOWSPECV4_NODE + || vty->node == BGP_FLOWSPECV6_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } @@ -3082,6 +3116,8 @@ void vtysh_init_vty(void) install_node(&zebra_node, NULL); install_node(&bgp_vpnv4_node, NULL); install_node(&bgp_vpnv6_node, NULL); + install_node(&bgp_flowspecv4_node, NULL); + install_node(&bgp_flowspecv6_node, NULL); install_node(&bgp_ipv4_node, NULL); install_node(&bgp_ipv4m_node, NULL); install_node(&bgp_ipv4l_node, NULL); @@ -3167,6 +3203,10 @@ void vtysh_init_vty(void) install_element(BGP_VPNV4_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VPNV6_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VPNV6_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_FLOWSPECV4_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_FLOWSPECV4_NODE, &vtysh_quit_bgpd_cmd); + install_element(BGP_FLOWSPECV6_NODE, &vtysh_exit_bgpd_cmd); + install_element(BGP_FLOWSPECV6_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd); @@ -3226,6 +3266,8 @@ void vtysh_init_vty(void) install_element(BGP_IPV4L_NODE, &vtysh_end_all_cmd); install_element(BGP_VPNV4_NODE, &vtysh_end_all_cmd); install_element(BGP_VPNV6_NODE, &vtysh_end_all_cmd); + install_element(BGP_FLOWSPECV4_NODE, &vtysh_end_all_cmd); + install_element(BGP_FLOWSPECV6_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6M_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6L_NODE, &vtysh_end_all_cmd); @@ -3299,6 +3341,8 @@ void vtysh_init_vty(void) install_element(BGP_NODE, &address_family_ipv6_vpn_cmd); install_element(BGP_NODE, &address_family_ipv6_labeled_unicast_cmd); install_element(BGP_NODE, &address_family_evpn_cmd); + install_element(BGP_NODE, &address_family_flowspecv4_cmd); + install_element(BGP_NODE, &address_family_flowspecv6_cmd); #if defined(HAVE_CUMULUS) install_element(BGP_NODE, &address_family_evpn2_cmd); #endif @@ -3311,6 +3355,8 @@ void vtysh_init_vty(void) install_element(BGP_IPV6M_NODE, &exit_address_family_cmd); install_element(BGP_EVPN_NODE, &exit_address_family_cmd); install_element(BGP_IPV6L_NODE, &exit_address_family_cmd); + install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd); + install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd); #if defined(HAVE_RPKI) install_element(CONFIG_NODE, &rpki_cmd); From d33fc23bf8d70bea0fabae541e127b4bdbc77a8d Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 7 Mar 2018 18:54:09 +0100 Subject: [PATCH 11/14] bgpd: support for json in show bgp ipv4 flowspec commands The json format is returd when requested from the two commands: - show bgp ipv4 flowspec - show bgp ipv4 flowspec detail Signed-off-by: Philippe Guibert --- bgpd/bgp_debug.c | 2 +- bgpd/bgp_flowspec.c | 2 +- bgpd/bgp_flowspec.h | 11 ++-- bgpd/bgp_flowspec_util.h | 3 +- bgpd/bgp_flowspec_vty.c | 108 +++++++++++++++++++++++++++++++-------- bgpd/bgp_route.c | 9 ++-- 6 files changed, 105 insertions(+), 30 deletions(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 8801028313..ae4ff5d67e 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -2223,7 +2223,7 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, bgp_fs_nlri_get_string((unsigned char *)fs->prefix.ptr, fs->prefix.prefixlen, return_string, - NLRI_STRING_FORMAT_DEBUG); + NLRI_STRING_FORMAT_DEBUG, NULL); snprintf(str, size, "FS %s Match{%s}", afi2str(afi), return_string); } else diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index d53271e851..5db7e37089 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -156,7 +156,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, p.u.prefix_flowspec.ptr, p.u.prefix_flowspec.prefixlen, return_string, - NLRI_STRING_FORMAT_MIN); + NLRI_STRING_FORMAT_MIN, NULL); snprintf(ec_string, BGP_FLOWSPEC_NLRI_STRING_MAX, "EC{none}"); if (attr && attr->ecommunity) { diff --git a/bgpd/bgp_flowspec.h b/bgpd/bgp_flowspec.h index 791ed2e693..392b321530 100644 --- a/bgpd/bgp_flowspec.h +++ b/bgpd/bgp_flowspec.h @@ -19,9 +19,11 @@ #ifndef _FRR_BGP_FLOWSPEC_H #define _FRR_BGP_FLOWSPEC_H -#define NLRI_STRING_FORMAT_LARGE 0 -#define NLRI_STRING_FORMAT_DEBUG 1 -#define NLRI_STRING_FORMAT_MIN 2 +#define NLRI_STRING_FORMAT_LARGE 0 +#define NLRI_STRING_FORMAT_DEBUG 1 +#define NLRI_STRING_FORMAT_MIN 2 +#define NLRI_STRING_FORMAT_JSON 3 +#define NLRI_STRING_FORMAT_JSON_SIMPLE 4 #define BGP_FLOWSPEC_NLRI_STRING_MAX 512 @@ -39,7 +41,8 @@ extern int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, unsigned long *total_cum); extern void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, - char *return_string, int format); + char *return_string, int format, + json_object *json_path); extern void route_vty_out_flowspec(struct vty *vty, struct prefix *p, struct bgp_info *binfo, diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h index 55a464a718..5d262dbbc7 100644 --- a/bgpd/bgp_flowspec_util.h +++ b/bgpd/bgp_flowspec_util.h @@ -26,7 +26,8 @@ enum bgp_flowspec_util_nlri_t { BGP_FLOWSPEC_VALIDATE_ONLY = 0, BGP_FLOWSPEC_RETURN_STRING = 1, - BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE = 2 + BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE = 2, + BGP_FLOWSPEC_RETURN_JSON = 3, }; diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 76ac0888b4..eae9bedcbd 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -79,7 +79,8 @@ static const struct message bgp_flowspec_display_min[] = { /* Parse FLOWSPEC NLRI*/ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, - char *return_string, int format) + char *return_string, int format, + json_object *json_path) { uint32_t offset = 0; int type; @@ -90,6 +91,7 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, char extra[2] = ""; char pre_extra[2] = ""; const struct message *bgp_flowspec_display; + enum bgp_flowspec_util_nlri_t type_util; if (format == NLRI_STRING_FORMAT_LARGE) { snprintf(pre_extra, sizeof(pre_extra), "\t"); @@ -97,6 +99,8 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, bgp_flowspec_display = bgp_flowspec_display_large; } else bgp_flowspec_display = bgp_flowspec_display_min; + /* if needed. type_util can be set to other values */ + type_util = BGP_FLOWSPEC_RETURN_STRING; error = 0; while (offset < len-1 && error >= 0) { type = nlri_content[offset]; @@ -105,12 +109,18 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, case FLOWSPEC_DEST_PREFIX: case FLOWSPEC_SRC_PREFIX: ret = bgp_flowspec_ip_address( - BGP_FLOWSPEC_RETURN_STRING, + type_util, nlri_content+offset, len - offset, local_string, &error); if (ret <= 0) break; + if (json_path) { + json_object_string_add(json_path, + lookup_msg(bgp_flowspec_display, type, ""), + local_string); + break; + } FS_STRING_UPDATE(count, ptr, format); ptr += sprintf(ptr, "%s%s %s%s", pre_extra, lookup_msg(bgp_flowspec_display, type, ""), @@ -122,12 +132,18 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, case FLOWSPEC_SRC_PORT: case FLOWSPEC_ICMP_TYPE: case FLOWSPEC_ICMP_CODE: - ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_RETURN_STRING, + ret = bgp_flowspec_op_decode(type_util, nlri_content+offset, len - offset, local_string, &error); if (ret <= 0) break; + if (json_path) { + json_object_string_add(json_path, + lookup_msg(bgp_flowspec_display, type, ""), + local_string); + break; + } FS_STRING_UPDATE(count, ptr, format); ptr += sprintf(ptr, "%s%s %s%s", pre_extra, lookup_msg(bgp_flowspec_display, @@ -136,12 +152,18 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, break; case FLOWSPEC_TCP_FLAGS: ret = bgp_flowspec_tcpflags_decode( - BGP_FLOWSPEC_RETURN_STRING, + type_util, nlri_content+offset, len - offset, local_string, &error); if (ret <= 0) break; + if (json_path) { + json_object_string_add(json_path, + lookup_msg(bgp_flowspec_display, type, ""), + local_string); + break; + } FS_STRING_UPDATE(count, ptr, format); ptr += sprintf(ptr, "%s%s %s%s", pre_extra, lookup_msg(bgp_flowspec_display, type, ""), @@ -150,12 +172,18 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, case FLOWSPEC_PKT_LEN: case FLOWSPEC_DSCP: ret = bgp_flowspec_op_decode( - BGP_FLOWSPEC_RETURN_STRING, + type_util, nlri_content + offset, len - offset, local_string, &error); if (ret <= 0) break; + if (json_path) { + json_object_string_add(json_path, + lookup_msg(bgp_flowspec_display, type, ""), + local_string); + break; + } FS_STRING_UPDATE(count, ptr, format); ptr += sprintf(ptr, "%s%s %s%s", pre_extra, lookup_msg(bgp_flowspec_display, @@ -164,12 +192,19 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, break; case FLOWSPEC_FRAGMENT: ret = bgp_flowspec_fragment_type_decode( - BGP_FLOWSPEC_RETURN_STRING, + type_util, nlri_content + offset, len - offset, local_string, &error); if (ret <= 0) break; + if (json_path) { + json_object_string_add(json_path, + lookup_msg(bgp_flowspec_display, + type, ""), + local_string); + break; + } FS_STRING_UPDATE(count, ptr, format); ptr += sprintf(ptr, "%s%s %s%s", pre_extra, lookup_msg(bgp_flowspec_display, @@ -191,11 +226,21 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, struct attr *attr; char return_string[BGP_FLOWSPEC_STRING_DISPLAY_MAX]; char *s; + json_object *json_nlri_path = NULL; + json_object *json_ecom_path = NULL; + json_object *json_time_path = NULL; + char timebuf[BGP_UPTIME_LEN]; /* Print prefix */ if (p != NULL) { if (p->family != AF_FLOWSPEC) return; + if (json_paths) { + if (display == NLRI_STRING_FORMAT_JSON) + json_nlri_path = json_object_new_object(); + else + json_nlri_path = json_paths; + } if (display == NLRI_STRING_FORMAT_LARGE) vty_out(vty, "BGP flowspec entry: (flags 0x%x)\n", binfo->flags); @@ -203,13 +248,16 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, p->u.prefix_flowspec.ptr, p->u.prefix_flowspec.prefixlen, return_string, - display); + display, + json_nlri_path); if (display == NLRI_STRING_FORMAT_LARGE) vty_out(vty, "%s", return_string); else if (display == NLRI_STRING_FORMAT_DEBUG) vty_out(vty, "%s", return_string); - else + else if (display == NLRI_STRING_FORMAT_MIN) vty_out(vty, " %-30s", return_string); + else if (json_paths && display == NLRI_STRING_FORMAT_JSON) + json_object_array_add(json_paths, json_nlri_path); } if (!binfo) return; @@ -222,16 +270,27 @@ void route_vty_out_flowspec(struct vty *vty, struct prefix *p, return; if (display == NLRI_STRING_FORMAT_LARGE) vty_out(vty, "\t%s\n", s); - else + else if (display == NLRI_STRING_FORMAT_MIN) vty_out(vty, "%s", s); + else if (json_paths) { + json_ecom_path = json_object_new_object(); + json_object_string_add(json_ecom_path, + "ecomlist", s); + if (display == NLRI_STRING_FORMAT_JSON) + json_object_array_add(json_paths, + json_ecom_path); + } XFREE(MTYPE_ECOMMUNITY_STR, s); } - if (display == NLRI_STRING_FORMAT_LARGE) { - char timebuf[BGP_UPTIME_LEN]; - - vty_out(vty, "\tup for %8s\n", - peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN, - 0, NULL)); + peer_uptime(binfo->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL); + if (display == NLRI_STRING_FORMAT_LARGE) + vty_out(vty, "\tup for %8s\n", timebuf); + else if (json_paths) { + json_time_path = json_object_new_object(); + json_object_string_add(json_time_path, + "time", timebuf); + if (display == NLRI_STRING_FORMAT_JSON) + json_object_array_add(json_paths, json_time_path); } } @@ -246,17 +305,18 @@ int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, struct bgp_node *rn; unsigned long total_count = 0; json_object *json_paths = NULL; - int display; + int display = NLRI_STRING_FORMAT_LARGE; if (type != bgp_show_type_detail) return CMD_SUCCESS; - display = NLRI_STRING_FORMAT_LARGE; - if (use_json) /* XXX */ - return CMD_SUCCESS; for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) { if (rn->info == NULL) continue; + if (use_json) { + json_paths = json_object_new_array(); + display = NLRI_STRING_FORMAT_JSON; + } for (ri = rn->info; ri; ri = ri->next) { total_count++; route_vty_out_flowspec(vty, &rn->p, @@ -264,8 +324,16 @@ int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, json_paths); } + if (use_json) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json_paths, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json_paths); + json_paths = NULL; + } } - if (total_count) + if (total_count && !use_json) vty_out(vty, "\nDisplayed %ld flowspec entries\n", total_count); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index db82386e72..ad3d57a9ae 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6319,7 +6319,9 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty, #endif } else if (p->family == AF_FLOWSPEC) { route_vty_out_flowspec(vty, p, NULL, - NLRI_STRING_FORMAT_MIN, json); + json ? + NLRI_STRING_FORMAT_JSON_SIMPLE : + NLRI_STRING_FORMAT_MIN, json); } else { if (!json) len = vty_out( @@ -6511,9 +6513,10 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo, "used"); } else vty_out(vty, "%-16s", inet_ntoa(attr->nexthop)); - } + } else if (safi == SAFI_FLOWSPEC) { + /* already done */ /* IPv4 Next Hop */ - else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { + } else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { if (json_paths) { json_nexthop_global = json_object_new_object(); From 98a9dbc7edcc9b56cf80814028e244bbc58beb53 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 15 Mar 2018 13:32:04 +0100 Subject: [PATCH 12/14] bgpd: enhance show bgp ipv4 flowspec This command gives detail about a FS entry which contains an IP that matches one of the rules of the FS entry. The output is the same output as when one does show bgp ipv4 flowspec detail Signed-off-by: Philippe Guibert --- bgpd/bgp_flowspec_util.c | 106 +++++++++++++++++++++++++++++++++++++++ bgpd/bgp_flowspec_util.h | 4 ++ bgpd/bgp_route.c | 13 +++++ 3 files changed, 123 insertions(+) diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c index 6b7a3d0063..7391a7b80a 100644 --- a/bgpd/bgp_flowspec_util.c +++ b/bgpd/bgp_flowspec_util.c @@ -21,7 +21,10 @@ #include "zebra.h" #include "prefix.h" + +#include "bgp_table.h" #include "bgp_flowspec_util.h" +#include "bgp_flowspec_private.h" static void hex2bin(uint8_t *hex, int *bin) { @@ -288,3 +291,106 @@ int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type, *error = -1; return offset; } + + +static bool bgp_flowspec_contains_prefix(struct prefix *pfs, + struct prefix *input, + int prefix_check) +{ + uint32_t offset = 0; + int type; + int ret = 0, error = 0; + uint8_t *nlri_content = (uint8_t *)pfs->u.prefix_flowspec.ptr; + size_t len = pfs->u.prefix_flowspec.prefixlen; + struct prefix compare; + + error = 0; + while (offset < len-1 && error >= 0) { + type = nlri_content[offset]; + offset++; + switch (type) { + case FLOWSPEC_DEST_PREFIX: + case FLOWSPEC_SRC_PREFIX: + memset(&compare, 0, sizeof(struct prefix)); + ret = bgp_flowspec_ip_address( + BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE, + nlri_content+offset, + len - offset, + &compare, &error); + if (ret <= 0) + break; + if (prefix_check && + compare.prefixlen != input->prefixlen) + break; + if (compare.family != input->family) + break; + if ((input->family == AF_INET) && + IPV4_ADDR_SAME(&input->u.prefix4, + &compare.u.prefix4)) + return true; + if ((input->family == AF_INET6) && + IPV6_ADDR_SAME(&input->u.prefix6.s6_addr, + &compare.u.prefix6.s6_addr)) + return true; + break; + case FLOWSPEC_IP_PROTOCOL: + case FLOWSPEC_PORT: + case FLOWSPEC_DEST_PORT: + case FLOWSPEC_SRC_PORT: + case FLOWSPEC_ICMP_TYPE: + case FLOWSPEC_ICMP_CODE: + ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY, + nlri_content+offset, + len - offset, + NULL, &error); + break; + case FLOWSPEC_TCP_FLAGS: + ret = bgp_flowspec_tcpflags_decode( + BGP_FLOWSPEC_VALIDATE_ONLY, + nlri_content+offset, + len - offset, + NULL, &error); + break; + case FLOWSPEC_PKT_LEN: + case FLOWSPEC_DSCP: + ret = bgp_flowspec_op_decode( + BGP_FLOWSPEC_VALIDATE_ONLY, + nlri_content + offset, + len - offset, NULL, + &error); + break; + case FLOWSPEC_FRAGMENT: + ret = bgp_flowspec_fragment_type_decode( + BGP_FLOWSPEC_VALIDATE_ONLY, + nlri_content + offset, + len - offset, NULL, + &error); + break; + default: + error = -1; + break; + } + offset += ret; + } + return false; +} + +struct bgp_node *bgp_flowspec_get_match_per_ip(afi_t afi, + struct bgp_table *rib, + struct prefix *match, + int prefix_check) +{ + struct bgp_node *rn; + struct prefix *prefix; + + for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) { + prefix = &rn->p; + + if (prefix->family != AF_FLOWSPEC) + continue; + + if (bgp_flowspec_contains_prefix(prefix, match, prefix_check)) + return rn; + } + return NULL; +} diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h index 5d262dbbc7..aa21461102 100644 --- a/bgpd/bgp_flowspec_util.h +++ b/bgpd/bgp_flowspec_util.h @@ -51,4 +51,8 @@ extern int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type, uint32_t max_len, void *result, int *error); +extern struct bgp_node *bgp_flowspec_get_match_per_ip(afi_t afi, + struct bgp_table *rib, + struct prefix *match, + int prefix_check); #endif /* _FRR_BGP_FLOWSPEC_UTIL_H */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ad3d57a9ae..e4769fe1d6 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -74,6 +74,7 @@ #include "bgpd/bgp_evpn.h" #include "bgpd/bgp_evpn_vty.h" #include "bgpd/bgp_flowspec.h" +#include "bgpd/bgp_flowspec_util.h" #ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_route_clippy.c" @@ -8724,6 +8725,18 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, bgp_unlock_node(rm); } + } else if (safi == SAFI_FLOWSPEC) { + rn = bgp_flowspec_get_match_per_ip(afi, rib, + &match, prefix_check); + if (rn != NULL) { + route_vty_out_flowspec(vty, &rn->p, + rn->info, use_json ? + NLRI_STRING_FORMAT_JSON : + NLRI_STRING_FORMAT_LARGE, + json_paths); + display++; + bgp_unlock_node(rn); + } } else { header = 1; From a83da8e19cdc0d74f0589f8644dbe5b79943498c Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 14 Mar 2018 10:33:40 +0100 Subject: [PATCH 13/14] bgpd: mp_unreach_nlri fs sent with no nexthop FS UNREACH message with 0 NLRI inside is sent after each peer establishment. FS can send NLRI messages with no nexthop. The commit fixes a message that is triggered by mistake if FS was about to be sent, then that message is not output. Also it fixes a typo. Signed-off-by: Philippe Guibert --- bgpd/bgp_attr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 639365588c..ef839dba6a 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2736,9 +2736,10 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, } break; default: - zlog_err( - "Bad nexthop when sening to %s, AFI %u SAFI %u nhlen %d", - peer->host, afi, safi, attr->mp_nexthop_len); + if (safi != SAFI_FLOWSPEC) + zlog_err( + "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d", + peer->host, afi, safi, attr->mp_nexthop_len); break; } From 362a06e37d82eae495b386f85aa5106b8dc7dffc Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 28 Mar 2018 14:35:56 +0200 Subject: [PATCH 14/14] bgpd: Flowspec display handlers uses snprintf snprintf routine is used widely, when the handler routine in charge of displaying the output is called. Signed-off-by: Philippe Guibert --- bgpd/bgp_flowspec_util.c | 108 ++++++++++++++++++++++++++++++--------- bgpd/bgp_flowspec_vty.c | 92 ++++++++++++++++++++++----------- 2 files changed, 147 insertions(+), 53 deletions(-) diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c index 7391a7b80a..007b27f17e 100644 --- a/bgpd/bgp_flowspec_util.c +++ b/bgpd/bgp_flowspec_util.c @@ -107,6 +107,8 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type, * return number of bytes analysed * if there is an error, the passed error param is used to give error: * -1 if decoding error, + * if result is a string, its assumed length + * is BGP_FLOWSPEC_STRING_DISPLAY_MAX */ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type, uint8_t *nlri_ptr, @@ -118,6 +120,8 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type, int loop = 0; char *ptr = (char *)result; /* for return_string */ uint32_t offset = 0; + int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX; + int len_written; *error = 0; do { @@ -134,15 +138,34 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type, *error = -1; switch (type) { case BGP_FLOWSPEC_RETURN_STRING: - if (loop) - ptr += sprintf(ptr, ", "); - if (op[5] == 1) - ptr += sprintf(ptr, "<"); - if (op[6] == 1) - ptr += sprintf(ptr, ">"); - if (op[7] == 1) - ptr += sprintf(ptr, "="); - ptr += sprintf(ptr, " %d ", value); + if (loop) { + len_written = snprintf(ptr, len_string, + ", "); + len_string -= len_written; + ptr += len_written; + } + if (op[5] == 1) { + len_written = snprintf(ptr, len_string, + "<"); + len_string -= len_written; + ptr += len_written; + } + if (op[6] == 1) { + len_written = snprintf(ptr, len_string, + ">"); + len_string -= len_written; + ptr += len_written; + } + if (op[7] == 1) { + len_written = snprintf(ptr, len_string, + "="); + len_string -= len_written; + ptr += len_written; + } + len_written = snprintf(ptr, len_string, + " %d ", value); + len_string -= len_written; + ptr += len_written; break; case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE: /* TODO : FS OPAQUE */ @@ -169,6 +192,8 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type, * return number of bytes analysed * if there is an error, the passed error param is used to give error: * -1 if decoding error, + * if result is a string, its assumed length + * is BGP_FLOWSPEC_STRING_DISPLAY_MAX */ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type, uint8_t *nlri_ptr, @@ -179,6 +204,8 @@ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type, int len, value_size, loop = 0, value; char *ptr = (char *)result; /* for return_string */ uint32_t offset = 0; + int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX; + int len_written; *error = 0; do { @@ -192,16 +219,37 @@ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type, value = hexstr2num(&nlri_ptr[offset], value_size); switch (type) { case BGP_FLOWSPEC_RETURN_STRING: - if (op[1] == 1 && loop != 0) - ptr += sprintf(ptr, ", and "); - else if (op[1] == 0 && loop != 0) - ptr += sprintf(ptr, ", or "); - ptr += sprintf(ptr, "tcp flags is "); - if (op[6] == 1) - ptr += sprintf(ptr, "not "); - if (op[7] == 1) - ptr += sprintf(ptr, "exactly match "); - ptr += sprintf(ptr, "%d", value); + if (op[1] == 1 && loop != 0) { + len_written = snprintf(ptr, len_string, + ", and "); + len_string -= len_written; + ptr += len_written; + } else if (op[1] == 0 && loop != 0) { + len_written = snprintf(ptr, len_string, + ", or "); + len_string -= len_written; + ptr += len_written; + } + len_written = snprintf(ptr, len_string, + "tcp flags is "); + len_string -= len_written; + ptr += len_written; + if (op[6] == 1) { + ptr += snprintf(ptr, len_string, + "not "); + len_string -= len_written; + ptr += len_written; + } + if (op[7] == 1) { + ptr += snprintf(ptr, len_string, + "exactly match "); + len_string -= len_written; + ptr += len_written; + } + ptr += snprintf(ptr, len_string, + "%d", value); + len_string -= len_written; + ptr += len_written; break; case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE: /* TODO : FS OPAQUE */ @@ -237,6 +285,8 @@ int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type, int len, value, value_size, loop = 0; char *ptr = (char *)result; /* for return_string */ uint32_t offset = 0; + int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX; + int len_written; *error = 0; do { @@ -262,16 +312,28 @@ int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type, case BGP_FLOWSPEC_RETURN_STRING: switch (value) { case 1: - ptr += sprintf(ptr, "dont-fragment"); + len_written = snprintf(ptr, len_string, + "dont-fragment"); + len_string -= len_written; + ptr += len_written; break; case 2: - ptr += sprintf(ptr, "is-fragment"); + len_written = snprintf(ptr, len_string, + "is-fragment"); + len_string -= len_written; + ptr += len_written; break; case 4: - ptr += sprintf(ptr, "first-fragment"); + len_written = snprintf(ptr, len_string, + "first-fragment"); + len_string -= len_written; + ptr += len_written; break; case 8: - ptr += sprintf(ptr, "last-fragment"); + len_written = snprintf(ptr, len_string, + "last-fragment"); + len_string -= len_written; + ptr += len_written; break; default: {} diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index eae9bedcbd..247da5d183 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -68,16 +68,28 @@ static const struct message bgp_flowspec_display_min[] = { {0} }; -#define FS_STRING_UPDATE(count, ptr, format) do { \ - if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) { \ - (ptr) += sprintf((ptr), ", "); \ - } else if (((format) == NLRI_STRING_FORMAT_MIN) && (count)) { \ - (ptr) += sprintf((ptr), " "); \ - } \ - count++; \ +#define FS_STRING_UPDATE(count, ptr, format, remaining_len) do { \ + int _len_written; \ + \ + if (((format) == NLRI_STRING_FORMAT_DEBUG) && (count)) {\ + _len_written = snprintf((ptr), (remaining_len), \ + ", "); \ + (remaining_len) -= _len_written; \ + (ptr) += _len_written; \ + } else if (((format) == NLRI_STRING_FORMAT_MIN) \ + && (count)) { \ + _len_written = snprintf((ptr), (remaining_len), \ + " "); \ + (remaining_len) -= _len_written; \ + (ptr) += _len_written; \ + } \ + count++; \ } while (0) -/* Parse FLOWSPEC NLRI*/ +/* Parse FLOWSPEC NLRI + * passed return_string string has assumed length + * BGP_FLOWSPEC_STRING_DISPLAY_MAX + */ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, char *return_string, int format, json_object *json_path) @@ -92,6 +104,8 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, char pre_extra[2] = ""; const struct message *bgp_flowspec_display; enum bgp_flowspec_util_nlri_t type_util; + int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX; + int len_written; if (format == NLRI_STRING_FORMAT_LARGE) { snprintf(pre_extra, sizeof(pre_extra), "\t"); @@ -121,10 +135,14 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, local_string); break; } - FS_STRING_UPDATE(count, ptr, format); - ptr += sprintf(ptr, "%s%s %s%s", pre_extra, - lookup_msg(bgp_flowspec_display, type, ""), - local_string, extra); + FS_STRING_UPDATE(count, ptr, format, len_string); + len_written = snprintf(ptr, len_string, "%s%s %s%s", + pre_extra, + lookup_msg(bgp_flowspec_display, + type, ""), + local_string, extra); + len_string -= len_written; + ptr += len_written; break; case FLOWSPEC_IP_PROTOCOL: case FLOWSPEC_PORT: @@ -144,11 +162,14 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, local_string); break; } - FS_STRING_UPDATE(count, ptr, format); - ptr += sprintf(ptr, "%s%s %s%s", pre_extra, - lookup_msg(bgp_flowspec_display, - type, ""), + FS_STRING_UPDATE(count, ptr, format, len_string); + len_written = snprintf(ptr, len_string, "%s%s %s%s", + pre_extra, + lookup_msg(bgp_flowspec_display, + type, ""), local_string, extra); + len_string -= len_written; + ptr += len_written; break; case FLOWSPEC_TCP_FLAGS: ret = bgp_flowspec_tcpflags_decode( @@ -160,14 +181,19 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, break; if (json_path) { json_object_string_add(json_path, - lookup_msg(bgp_flowspec_display, type, ""), + lookup_msg(bgp_flowspec_display, + type, ""), local_string); break; } - FS_STRING_UPDATE(count, ptr, format); - ptr += sprintf(ptr, "%s%s %s%s", pre_extra, - lookup_msg(bgp_flowspec_display, type, ""), - local_string, extra); + FS_STRING_UPDATE(count, ptr, format, len_string); + len_written = snprintf(ptr, len_string, "%s%s %s%s", + pre_extra, + lookup_msg(bgp_flowspec_display, + type, ""), + local_string, extra); + len_string -= len_written; + ptr += len_written; break; case FLOWSPEC_PKT_LEN: case FLOWSPEC_DSCP: @@ -184,11 +210,14 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, local_string); break; } - FS_STRING_UPDATE(count, ptr, format); - ptr += sprintf(ptr, "%s%s %s%s", pre_extra, - lookup_msg(bgp_flowspec_display, - type, ""), + FS_STRING_UPDATE(count, ptr, format, len_string); + len_written = snprintf(ptr, len_string, "%s%s %s%s", + pre_extra, + lookup_msg(bgp_flowspec_display, + type, ""), local_string, extra); + len_string -= len_written; + ptr += len_written; break; case FLOWSPEC_FRAGMENT: ret = bgp_flowspec_fragment_type_decode( @@ -205,11 +234,14 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, local_string); break; } - FS_STRING_UPDATE(count, ptr, format); - ptr += sprintf(ptr, "%s%s %s%s", pre_extra, - lookup_msg(bgp_flowspec_display, - type, ""), - local_string, extra); + FS_STRING_UPDATE(count, ptr, format, len_string); + len_written = snprintf(ptr, len_string, "%s%s %s%s", + pre_extra, + lookup_msg(bgp_flowspec_display, + type, ""), + local_string, extra); + len_string -= len_written; + ptr += len_written; break; default: error = -1;