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
, bool withdraw
)
95 /* Start processing the NLRI - there may be multiple in the MP_REACH */
97 lim
= pnt
+ packet
->length
;
102 * All other AFI/SAFI's treat no attribute as a implicit
103 * withdraw. Flowspec should as well.
108 if (packet
->length
>= FLOWSPEC_NLRI_SIZELIMIT_EXTENDED
) {
109 flog_err(EC_BGP_FLOWSPEC_PACKET
,
110 "BGP flowspec nlri length maximum reached (%u)",
112 return BGP_NLRI_PARSE_ERROR_FLOWSPEC_NLRI_SIZELIMIT
;
115 for (; pnt
< lim
; pnt
+= psize
) {
116 /* Clear prefix structure. */
117 memset(&p
, 0, sizeof(p
));
119 /* All FlowSpec NLRI begin with length. */
121 return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW
;
124 if (psize
>= FLOWSPEC_NLRI_SIZELIMIT
) {
129 /* When packet overflow occur return immediately. */
130 if (pnt
+ psize
> lim
) {
132 EC_BGP_FLOWSPEC_PACKET
,
133 "Flowspec NLRI length inconsistent ( size %u seen)",
135 return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW
;
139 flog_err(EC_BGP_FLOWSPEC_PACKET
,
140 "Flowspec NLRI length 0 which makes no sense");
141 return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW
;
144 if (bgp_fs_nlri_validate(pnt
, psize
, afi
) < 0) {
146 EC_BGP_FLOWSPEC_PACKET
,
147 "Bad flowspec format or NLRI options not supported");
148 return BGP_NLRI_PARSE_ERROR_FLOWSPEC_BAD_FORMAT
;
150 p
.family
= AF_FLOWSPEC
;
152 /* Flowspec encoding is in bytes */
153 p
.u
.prefix_flowspec
.prefixlen
= psize
;
154 p
.u
.prefix_flowspec
.family
= afi2family(afi
);
155 temp
= XCALLOC(MTYPE_TMP
, psize
);
156 memcpy(temp
, pnt
, psize
);
157 p
.u
.prefix_flowspec
.ptr
= (uintptr_t) temp
;
159 if (BGP_DEBUG(flowspec
, FLOWSPEC
)) {
160 char return_string
[BGP_FLOWSPEC_NLRI_STRING_MAX
];
161 char local_string
[BGP_FLOWSPEC_NLRI_STRING_MAX
*2+16];
162 char ec_string
[BGP_FLOWSPEC_NLRI_STRING_MAX
];
165 bgp_fs_nlri_get_string((unsigned char *)
166 p
.u
.prefix_flowspec
.ptr
,
167 p
.u
.prefix_flowspec
.prefixlen
,
169 NLRI_STRING_FORMAT_MIN
, NULL
,
171 snprintf(ec_string
, sizeof(ec_string
),
173 if (attr
&& bgp_attr_get_ecommunity(attr
)) {
174 s
= ecommunity_ecom2str(
175 bgp_attr_get_ecommunity(attr
),
176 ECOMMUNITY_FORMAT_ROUTE_MAP
, 0);
177 snprintf(ec_string
, sizeof(ec_string
),
179 s
== NULL
? "none" : s
);
182 ecommunity_strfree(&s
);
184 snprintf(local_string
, sizeof(local_string
),
185 "FS Rx %s %s %s %s", withdraw
?
187 afi2str(afi
), return_string
,
188 attr
!= NULL
? ec_string
: "");
189 zlog_info("%s", local_string
);
191 /* Process the route. */
193 bgp_update(peer
, &p
, 0, attr
, afi
, safi
,
194 ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
, NULL
,
197 bgp_withdraw(peer
, &p
, 0, afi
, safi
, ZEBRA_ROUTE_BGP
,
198 BGP_ROUTE_NORMAL
, NULL
, NULL
, 0, NULL
);
200 return BGP_NLRI_PARSE_OK
;