Merge pull request #1817 from pguibert6WIND/flowspec_client

Flowspec client
This commit is contained in:
Vincent JARDIN 2018-03-30 15:13:36 +02:00 committed by GitHub
commit 588f0b6b49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1796 additions and 34 deletions

View File

@ -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_keepalives.c bgp_io.c bgp_flowspec.c bgp_flowspec_util.c \
bgp_flowspec_vty.c
noinst_HEADERS = \
bgp_memory.h \
@ -99,7 +100,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 bgp_flowspec_util.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@

View File

@ -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,14 +2729,17 @@ 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;
}
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;
}
@ -2756,6 +2769,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);
}

View File

@ -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, NULL);
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));

View File

@ -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

View File

@ -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;

View File

@ -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
@ -53,7 +62,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 {

195
bgpd/bgp_flowspec.c Normal file
View File

@ -0,0 +1,195 @@
/* 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 <zebra.h>
#include "prefix.h"
#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"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_debug.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");
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;
}
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;
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, NULL);
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,
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;
}

50
bgpd/bgp_flowspec.h Normal file
View File

@ -0,0 +1,50 @@
/* 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
#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
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,
json_object *json_path);
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 */

View File

@ -0,0 +1,44 @@
/* 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
/* Flowspec raffic action bit*/
#define FLOWSPEC_TRAFFIC_ACTION_TERMINAL 1
#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 */

458
bgpd/bgp_flowspec_util.c Normal file
View File

@ -0,0 +1,458 @@
/* 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_table.h"
#include "bgp_flowspec_util.h"
#include "bgp_flowspec_private.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,
* 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,
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;
int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
int len_written;
*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) {
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 */
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,
* 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,
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;
int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
int len_written;
*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) {
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 */
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;
int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
int len_written;
*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:
len_written = snprintf(ptr, len_string,
"dont-fragment");
len_string -= len_written;
ptr += len_written;
break;
case 2:
len_written = snprintf(ptr, len_string,
"is-fragment");
len_string -= len_written;
ptr += len_written;
break;
case 4:
len_written = snprintf(ptr, len_string,
"first-fragment");
len_string -= len_written;
ptr += len_written;
break;
case 8:
len_written = snprintf(ptr, len_string,
"last-fragment");
len_string -= len_written;
ptr += len_written;
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;
}
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;
}

58
bgpd/bgp_flowspec_util.h Normal file
View File

@ -0,0 +1,58 @@
/* 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,
BGP_FLOWSPEC_RETURN_JSON = 3,
};
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);
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 */

414
bgpd/bgp_flowspec_vty.c Normal file
View File

@ -0,0 +1,414 @@
/* 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 <zebra.h>
#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"
#include "bgpd/bgp_debug.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, 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
* 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)
{
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;
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");
snprintf(extra, sizeof(extra), "\n");
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];
offset++;
switch (type) {
case FLOWSPEC_DEST_PREFIX:
case FLOWSPEC_SRC_PREFIX:
ret = bgp_flowspec_ip_address(
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, 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:
case FLOWSPEC_DEST_PORT:
case FLOWSPEC_SRC_PORT:
case FLOWSPEC_ICMP_TYPE:
case FLOWSPEC_ICMP_CODE:
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, 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(
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, 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:
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, 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(
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, 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;
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;
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);
bgp_fs_nlri_get_string((unsigned char *)
p->u.prefix_flowspec.ptr,
p->u.prefix_flowspec.prefixlen,
return_string,
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 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;
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 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);
}
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);
}
}
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 = NLRI_STRING_FORMAT_LARGE;
if (type != bgp_show_type_detail)
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,
ri, display,
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 && !use_json)
vty_out(vty,
"\nDisplayed %ld flowspec entries\n",
total_count);
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);
}

View File

@ -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")

View File

@ -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 */

View File

@ -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 "

View File

@ -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

View File

@ -73,6 +73,8 @@
#include "bgpd/bgp_encap_tlv.h"
#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"
@ -5551,7 +5553,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 +5592,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 +5821,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 +5867,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) {
@ -6308,6 +6318,11 @@ 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,
json ?
NLRI_STRING_FORMAT_JSON_SIMPLE :
NLRI_STRING_FORMAT_MIN, json);
} else {
if (!json)
len = vty_out(
@ -6499,9 +6514,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();
@ -8421,6 +8437,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;
@ -8703,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;
@ -10417,6 +10451,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 [<view|vrf> 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 [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] "
@ -11431,6 +11491,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)

View File

@ -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,
};

View File

@ -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 [<unicast|multicast|vpn|labeled-unicast>]",
"Enter Address Family command mode\n"
"Address Family\n"
BGP_SAFI_WITH_LABEL_HELP_STR)
address_family_ipv4_safi_cmd,
"address-family ipv4 [<unicast|multicast|vpn|labeled-unicast|flowspec>]",
"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 [<unicast|multicast|vpn|labeled-unicast>]",
"Enter Address Family command mode\n"
"Address Family\n"
BGP_SAFI_WITH_LABEL_HELP_STR)
address_family_ipv6_safi_cmd,
"address-family ipv6 [<unicast|multicast|vpn|labeled-unicast|flowspec>]",
"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" */

View File

@ -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 "<unicast|multicast|vpn|labeled-unicast>"
#define BGP_SAFI_WITH_LABEL_CMD_STR "<unicast|multicast|vpn|labeled-unicast|flowspec>"
#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);

View File

@ -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();

View File

@ -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;

View File

@ -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:

View File

@ -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 */
};

View File

@ -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)
{

View File

@ -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)

View File

@ -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";
}
@ -539,6 +541,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 +601,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 +619,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 +670,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 +699,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 +1265,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 +1448,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(&copy, 0, sizeof(copy));
prefix_copy(&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. */

View File

@ -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

View File

@ -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])

View File

@ -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;
}

View File

@ -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);

View File

@ -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);