mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-04 10:09:25 +00:00
Merge pull request #1817 from pguibert6WIND/flowspec_client
Flowspec client
This commit is contained in:
commit
588f0b6b49
@ -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@
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
195
bgpd/bgp_flowspec.c
Normal 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
50
bgpd/bgp_flowspec.h
Normal 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 */
|
44
bgpd/bgp_flowspec_private.h
Normal file
44
bgpd/bgp_flowspec_private.h
Normal 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
458
bgpd/bgp_flowspec_util.c
Normal 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
58
bgpd/bgp_flowspec_util.h
Normal 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
414
bgpd/bgp_flowspec_vty.c
Normal 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);
|
||||
}
|
@ -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")
|
||||
|
@ -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 */
|
||||
|
@ -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 "
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
||||
|
105
bgpd/bgp_vty.c
105
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 [<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" */
|
||||
|
@ -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);
|
||||
|
21
bgpd/bgpd.c
21
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();
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
88
lib/prefix.c
88
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";
|
||||
}
|
||||
@ -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(©, 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. */
|
||||
|
19
lib/prefix.h
19
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
|
||||
|
12
lib/table.c
12
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])
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user