1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* BGP FlowSpec for packet handling
4 * Copyright (C) 2017 ChinaTelecom SDN Group
5 * Copyright (C) 2018 6WIND
12 #include "lib_errors.h"
14 #include "bgpd/bgpd.h"
15 #include "bgpd/bgp_route.h"
16 #include "bgpd/bgp_flowspec.h"
17 #include "bgpd/bgp_flowspec_util.h"
18 #include "bgpd/bgp_flowspec_private.h"
19 #include "bgpd/bgp_ecommunity.h"
20 #include "bgpd/bgp_debug.h"
21 #include "bgpd/bgp_errors.h"
23 static int bgp_fs_nlri_validate(uint8_t *nlri_content
, uint32_t len
,
28 int ret
= 0, error
= 0;
30 while (offset
< len
-1) {
31 type
= nlri_content
[offset
];
34 case FLOWSPEC_DEST_PREFIX
:
35 case FLOWSPEC_SRC_PREFIX
:
36 ret
= bgp_flowspec_ip_address(
37 BGP_FLOWSPEC_VALIDATE_ONLY
,
38 nlri_content
+ offset
,
39 len
- offset
, NULL
, &error
,
42 case FLOWSPEC_FLOW_LABEL
:
45 ret
= bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY
,
46 nlri_content
+ offset
,
47 len
- offset
, NULL
, &error
);
49 case FLOWSPEC_IP_PROTOCOL
:
51 case FLOWSPEC_DEST_PORT
:
52 case FLOWSPEC_SRC_PORT
:
53 case FLOWSPEC_ICMP_TYPE
:
54 case FLOWSPEC_ICMP_CODE
:
55 ret
= bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY
,
56 nlri_content
+ offset
,
57 len
- offset
, NULL
, &error
);
59 case FLOWSPEC_TCP_FLAGS
:
60 case FLOWSPEC_FRAGMENT
:
61 ret
= bgp_flowspec_bitmask_decode(
62 BGP_FLOWSPEC_VALIDATE_ONLY
,
63 nlri_content
+ offset
,
64 len
- offset
, NULL
, &error
);
66 case FLOWSPEC_PKT_LEN
:
68 ret
= bgp_flowspec_op_decode(
69 BGP_FLOWSPEC_VALIDATE_ONLY
,
70 nlri_content
+ offset
,
71 len
- offset
, NULL
, &error
);
84 int bgp_nlri_parse_flowspec(struct peer
*peer
, struct attr
*attr
,
85 struct bgp_nlri
*packet
, int withdraw
)
95 /* Start processing the NLRI - there may be multiple in the MP_REACH */
97 lim
= pnt
+ packet
->length
;
101 if (packet
->length
>= FLOWSPEC_NLRI_SIZELIMIT_EXTENDED
) {
102 flog_err(EC_BGP_FLOWSPEC_PACKET
,
103 "BGP flowspec nlri length maximum reached (%u)",
105 return BGP_NLRI_PARSE_ERROR_FLOWSPEC_NLRI_SIZELIMIT
;
108 for (; pnt
< lim
; pnt
+= psize
) {
109 /* Clear prefix structure. */
110 memset(&p
, 0, sizeof(p
));
112 /* All FlowSpec NLRI begin with length. */
114 return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW
;
117 if (psize
>= FLOWSPEC_NLRI_SIZELIMIT
) {
122 /* When packet overflow occur return immediately. */
123 if (pnt
+ psize
> lim
) {
125 EC_BGP_FLOWSPEC_PACKET
,
126 "Flowspec NLRI length inconsistent ( size %u seen)",
128 return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW
;
130 if (bgp_fs_nlri_validate(pnt
, psize
, afi
) < 0) {
132 EC_BGP_FLOWSPEC_PACKET
,
133 "Bad flowspec format or NLRI options not supported");
134 return BGP_NLRI_PARSE_ERROR_FLOWSPEC_BAD_FORMAT
;
136 p
.family
= AF_FLOWSPEC
;
138 /* Flowspec encoding is in bytes */
139 p
.u
.prefix_flowspec
.prefixlen
= psize
;
140 p
.u
.prefix_flowspec
.family
= afi2family(afi
);
141 temp
= XCALLOC(MTYPE_TMP
, psize
);
142 memcpy(temp
, pnt
, psize
);
143 p
.u
.prefix_flowspec
.ptr
= (uintptr_t) temp
;
145 if (BGP_DEBUG(flowspec
, FLOWSPEC
)) {
146 char return_string
[BGP_FLOWSPEC_NLRI_STRING_MAX
];
147 char local_string
[BGP_FLOWSPEC_NLRI_STRING_MAX
*2+16];
148 char ec_string
[BGP_FLOWSPEC_NLRI_STRING_MAX
];
151 bgp_fs_nlri_get_string((unsigned char *)
152 p
.u
.prefix_flowspec
.ptr
,
153 p
.u
.prefix_flowspec
.prefixlen
,
155 NLRI_STRING_FORMAT_MIN
, NULL
,
157 snprintf(ec_string
, sizeof(ec_string
),
159 if (attr
&& bgp_attr_get_ecommunity(attr
)) {
160 s
= ecommunity_ecom2str(
161 bgp_attr_get_ecommunity(attr
),
162 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
163 snprintf(ec_string
, sizeof(ec_string
),
165 s
== NULL
? "none" : s
);
168 ecommunity_strfree(&s
);
170 snprintf(local_string
, sizeof(local_string
),
171 "FS Rx %s %s %s %s", withdraw
?
173 afi2str(afi
), return_string
,
174 attr
!= NULL
? ec_string
: "");
175 zlog_info("%s", local_string
);
177 /* Process the route. */
179 bgp_update(peer
, &p
, 0, attr
, afi
, safi
,
180 ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
, NULL
,
183 bgp_withdraw(peer
, &p
, 0, attr
, afi
, safi
,
184 ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
, NULL
,
187 return BGP_NLRI_PARSE_OK
;