mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-03 06:59:21 +00:00
bgpd: add flowspec utilities to decode, convert fs nlri
The FS nlri is depicted so as to be able to be in readable format, either by human, or by some other ( remote daemon ?). This work is a derived work from [0]. Initially done for validation only, this work is extended. The FS NLRI is able to decode addresses, numbers ( protocols, ports, tcp values) combined ( or not) with operators. This makes possible to have a NLRI entry for a set of ports, and/or for an other set of value of port. This implementation mainly brings the API visible. The API should be consistent across the various usages. [0] https://github.com/chinatelecom-sdn-group/quagga_flowspec/ Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com> Signed-off-by: jaydom <chinatelecom-sdn-group@github.com>
This commit is contained in:
parent
f77af2c3f2
commit
034cdee950
@ -86,7 +86,7 @@ libbgp_a_SOURCES = \
|
||||
bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
|
||||
bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \
|
||||
bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c bgp_rd.c \
|
||||
bgp_keepalives.c bgp_io.c bgp_flowspec.c
|
||||
bgp_keepalives.c bgp_io.c bgp_flowspec.c bgp_flowspec_util.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
bgp_memory.h \
|
||||
@ -99,7 +99,7 @@ noinst_HEADERS = \
|
||||
bgp_updgrp.h bgp_bfd.h bgp_encap_tlv.h bgp_encap_types.h \
|
||||
$(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \
|
||||
bgp_vpn.h bgp_label.h bgp_rd.h bgp_evpn_private.h bgp_keepalives.h \
|
||||
bgp_io.h bgp_flowspec.h bgp_flowspec_private.h
|
||||
bgp_io.h bgp_flowspec.h bgp_flowspec_private.h bgp_flowspec_util.h
|
||||
|
||||
bgpd_SOURCES = bgp_main.c
|
||||
bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@
|
||||
|
290
bgpd/bgp_flowspec_util.c
Normal file
290
bgpd/bgp_flowspec_util.c
Normal file
@ -0,0 +1,290 @@
|
||||
/* BGP FlowSpec Utilities
|
||||
* Portions:
|
||||
* Copyright (C) 2017 ChinaTelecom SDN Group
|
||||
* Copyright (C) 2018 6WIND
|
||||
*
|
||||
* FRRouting is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRRouting is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "zebra.h"
|
||||
|
||||
#include "prefix.h"
|
||||
#include "bgp_flowspec_util.h"
|
||||
|
||||
static void hex2bin(uint8_t *hex, int *bin)
|
||||
{
|
||||
int remainder = *hex;
|
||||
int i = 0;
|
||||
|
||||
while (remainder >= 1 && i < 8) {
|
||||
bin[7-i] = remainder % 2;
|
||||
remainder = remainder / 2;
|
||||
i++;
|
||||
}
|
||||
for (; i < 8; i++)
|
||||
bin[7-i] = 0;
|
||||
}
|
||||
|
||||
static int hexstr2num(uint8_t *hexstr, int len)
|
||||
{
|
||||
int i = 0;
|
||||
int num = 0;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
num = hexstr[i] + 16*16*num;
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* handle the flowspec address src/dst or generic address NLRI
|
||||
* return number of bytes analysed ( >= 0).
|
||||
*/
|
||||
int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
|
||||
uint8_t *nlri_ptr,
|
||||
uint32_t max_len,
|
||||
void *result, int *error)
|
||||
{
|
||||
char *display = (char *)result; /* for return_string */
|
||||
struct prefix *prefix = (struct prefix *)result;
|
||||
uint32_t offset = 0;
|
||||
struct prefix prefix_local;
|
||||
int psize;
|
||||
|
||||
*error = 0;
|
||||
memset(&prefix_local, 0, sizeof(struct prefix));
|
||||
/* read the prefix length */
|
||||
prefix_local.prefixlen = nlri_ptr[offset];
|
||||
psize = PSIZE(prefix_local.prefixlen);
|
||||
offset++;
|
||||
/* TODO Flowspec IPv6 Support */
|
||||
prefix_local.family = AF_INET;
|
||||
/* Prefix length check. */
|
||||
if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8)
|
||||
*error = -1;
|
||||
/* When packet overflow occur return immediately. */
|
||||
if (psize + offset > max_len)
|
||||
*error = -1;
|
||||
/* Defensive coding, double-check
|
||||
* the psize fits in a struct prefix
|
||||
*/
|
||||
if (psize > (ssize_t)sizeof(prefix_local.u))
|
||||
*error = -1;
|
||||
memcpy(&prefix_local.u.prefix, &nlri_ptr[offset], psize);
|
||||
offset += psize;
|
||||
switch (type) {
|
||||
case BGP_FLOWSPEC_RETURN_STRING:
|
||||
prefix2str(&prefix_local, display,
|
||||
BGP_FLOWSPEC_STRING_DISPLAY_MAX);
|
||||
break;
|
||||
case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
|
||||
PREFIX_COPY_IPV4(prefix, &prefix_local)
|
||||
break;
|
||||
case BGP_FLOWSPEC_VALIDATE_ONLY:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle the flowspec operator NLRI
|
||||
* return number of bytes analysed
|
||||
* if there is an error, the passed error param is used to give error:
|
||||
* -1 if decoding error,
|
||||
*/
|
||||
int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
|
||||
uint8_t *nlri_ptr,
|
||||
uint32_t max_len,
|
||||
void *result, int *error)
|
||||
{
|
||||
int op[8];
|
||||
int len, value, value_size;
|
||||
int loop = 0;
|
||||
char *ptr = (char *)result; /* for return_string */
|
||||
uint32_t offset = 0;
|
||||
|
||||
*error = 0;
|
||||
do {
|
||||
hex2bin(&nlri_ptr[offset], op);
|
||||
offset++;
|
||||
len = 2*op[2]+op[3];
|
||||
value_size = 1 << len;
|
||||
value = hexstr2num(&nlri_ptr[offset], value_size);
|
||||
/* can not be < and > at the same time */
|
||||
if (op[5] == 1 && op[6] == 1)
|
||||
*error = -1;
|
||||
/* if first element, AND bit can not be set */
|
||||
if (op[1] == 1 && loop == 0)
|
||||
*error = -1;
|
||||
switch (type) {
|
||||
case BGP_FLOWSPEC_RETURN_STRING:
|
||||
if (loop)
|
||||
ptr += sprintf(ptr, ", ");
|
||||
if (op[5] == 1)
|
||||
ptr += sprintf(ptr, "<");
|
||||
if (op[6] == 1)
|
||||
ptr += sprintf(ptr, ">");
|
||||
if (op[7] == 1)
|
||||
ptr += sprintf(ptr, "=");
|
||||
ptr += sprintf(ptr, " %d ", value);
|
||||
break;
|
||||
case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
|
||||
/* TODO : FS OPAQUE */
|
||||
break;
|
||||
case BGP_FLOWSPEC_VALIDATE_ONLY:
|
||||
default:
|
||||
/* no action */
|
||||
break;
|
||||
}
|
||||
offset += value_size;
|
||||
loop++;
|
||||
} while (op[0] == 0 && offset < max_len - 1);
|
||||
if (offset > max_len)
|
||||
*error = -1;
|
||||
/* use error parameter to count the number of entries */
|
||||
if (*error == 0)
|
||||
*error = loop;
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* handle the flowspec tcpflags field
|
||||
* return number of bytes analysed
|
||||
* if there is an error, the passed error param is used to give error:
|
||||
* -1 if decoding error,
|
||||
*/
|
||||
int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
|
||||
uint8_t *nlri_ptr,
|
||||
uint32_t max_len,
|
||||
void *result, int *error)
|
||||
{
|
||||
int op[8];
|
||||
int len, value_size, loop = 0, value;
|
||||
char *ptr = (char *)result; /* for return_string */
|
||||
uint32_t offset = 0;
|
||||
|
||||
*error = 0;
|
||||
do {
|
||||
hex2bin(&nlri_ptr[offset], op);
|
||||
/* if first element, AND bit can not be set */
|
||||
if (op[1] == 1 && loop == 0)
|
||||
*error = -1;
|
||||
offset++;
|
||||
len = 2 * op[2] + op[3];
|
||||
value_size = 1 << len;
|
||||
value = hexstr2num(&nlri_ptr[offset], value_size);
|
||||
switch (type) {
|
||||
case BGP_FLOWSPEC_RETURN_STRING:
|
||||
if (op[1] == 1 && loop != 0)
|
||||
ptr += sprintf(ptr, ", and ");
|
||||
else if (op[1] == 0 && loop != 0)
|
||||
ptr += sprintf(ptr, ", or ");
|
||||
ptr += sprintf(ptr, "tcp flags is ");
|
||||
if (op[6] == 1)
|
||||
ptr += sprintf(ptr, "not ");
|
||||
if (op[7] == 1)
|
||||
ptr += sprintf(ptr, "exactly match ");
|
||||
ptr += sprintf(ptr, "%d", value);
|
||||
break;
|
||||
case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
|
||||
/* TODO : FS OPAQUE */
|
||||
break;
|
||||
case BGP_FLOWSPEC_VALIDATE_ONLY:
|
||||
default:
|
||||
/* no action */
|
||||
break;
|
||||
}
|
||||
offset += value_size;
|
||||
loop++;
|
||||
} while (op[0] == 0 && offset < max_len - 1);
|
||||
if (offset > max_len)
|
||||
*error = -1;
|
||||
/* use error parameter to count the number of entries */
|
||||
if (*error == 0)
|
||||
*error = loop;
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle the flowspec fragment type field
|
||||
* return error (returned values are invalid) or number of bytes analysed
|
||||
* -1 if error in decoding
|
||||
* >= 0 : number of bytes analysed (ok).
|
||||
*/
|
||||
int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
|
||||
uint8_t *nlri_ptr,
|
||||
uint32_t max_len,
|
||||
void *result, int *error)
|
||||
{
|
||||
int op[8];
|
||||
int len, value, value_size, loop = 0;
|
||||
char *ptr = (char *)result; /* for return_string */
|
||||
uint32_t offset = 0;
|
||||
|
||||
*error = 0;
|
||||
do {
|
||||
hex2bin(&nlri_ptr[offset], op);
|
||||
offset++;
|
||||
len = 2 * op[2] + op[3];
|
||||
value_size = 1 << len;
|
||||
value = hexstr2num(&nlri_ptr[offset], value_size);
|
||||
if (value != 1 && value != 2 && value != 4 && value != 8)
|
||||
*error = -1;
|
||||
offset += value_size;
|
||||
/* TODO : as per RFC5574 : first Fragment bits are Reserved
|
||||
* does that mean that it is not possible
|
||||
* to handle multiple occurences ?
|
||||
* as of today, we only grab the first TCP fragment
|
||||
*/
|
||||
if (loop) {
|
||||
*error = -2;
|
||||
loop++;
|
||||
continue;
|
||||
}
|
||||
switch (type) {
|
||||
case BGP_FLOWSPEC_RETURN_STRING:
|
||||
switch (value) {
|
||||
case 1:
|
||||
ptr += sprintf(ptr, "dont-fragment");
|
||||
break;
|
||||
case 2:
|
||||
ptr += sprintf(ptr, "is-fragment");
|
||||
break;
|
||||
case 4:
|
||||
ptr += sprintf(ptr, "first-fragment");
|
||||
break;
|
||||
case 8:
|
||||
ptr += sprintf(ptr, "last-fragment");
|
||||
break;
|
||||
default:
|
||||
{}
|
||||
}
|
||||
break;
|
||||
case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
|
||||
/* TODO : FS OPAQUE */
|
||||
break;
|
||||
case BGP_FLOWSPEC_VALIDATE_ONLY:
|
||||
default:
|
||||
/* no action */
|
||||
break;
|
||||
}
|
||||
loop++;
|
||||
} while (op[0] == 0 && offset < max_len - 1);
|
||||
if (offset > max_len)
|
||||
*error = -1;
|
||||
return offset;
|
||||
}
|
53
bgpd/bgp_flowspec_util.h
Normal file
53
bgpd/bgp_flowspec_util.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* BGP Flowspec header for utilities
|
||||
* Copyright (C) 2018 6WIND
|
||||
*
|
||||
* FRRouting is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRRouting is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRR_BGP_FLOWSPEC_UTIL_H
|
||||
#define _FRR_BGP_FLOWSPEC_UTIL_H
|
||||
|
||||
#include "zclient.h"
|
||||
|
||||
#define BGP_FLOWSPEC_STRING_DISPLAY_MAX 512
|
||||
|
||||
enum bgp_flowspec_util_nlri_t {
|
||||
BGP_FLOWSPEC_VALIDATE_ONLY = 0,
|
||||
BGP_FLOWSPEC_RETURN_STRING = 1,
|
||||
BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE = 2
|
||||
};
|
||||
|
||||
|
||||
extern int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
|
||||
uint8_t *nlri_ptr,
|
||||
uint32_t max_len,
|
||||
void *result, int *error);
|
||||
|
||||
extern int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
|
||||
uint8_t *nlri_ptr,
|
||||
uint32_t max_len,
|
||||
void *result, int *error);
|
||||
|
||||
extern int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
|
||||
uint8_t *nlri_ptr,
|
||||
uint32_t max_len,
|
||||
void *result, int *error);
|
||||
|
||||
extern int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
|
||||
uint8_t *nlri_ptr,
|
||||
uint32_t max_len,
|
||||
void *result, int *error);
|
||||
|
||||
#endif /* _FRR_BGP_FLOWSPEC_UTIL_H */
|
Loading…
Reference in New Issue
Block a user