Line data Source code
1 : /* BGP FlowSpec for packet handling
2 : * Portions:
3 : * Copyright (C) 2017 ChinaTelecom SDN Group
4 : * Copyright (C) 2018 6WIND
5 : *
6 : * FRRouting is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by the
8 : * Free Software Foundation; either version 2, or (at your option) any
9 : * later version.
10 : *
11 : * FRRouting is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License along
17 : * with this program; see the file COPYING; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : */
20 :
21 : #include <zebra.h>
22 : #include <math.h>
23 :
24 : #include "prefix.h"
25 : #include "lib_errors.h"
26 :
27 : #include "bgpd/bgpd.h"
28 : #include "bgpd/bgp_route.h"
29 : #include "bgpd/bgp_flowspec.h"
30 : #include "bgpd/bgp_flowspec_util.h"
31 : #include "bgpd/bgp_flowspec_private.h"
32 : #include "bgpd/bgp_ecommunity.h"
33 : #include "bgpd/bgp_debug.h"
34 : #include "bgpd/bgp_errors.h"
35 :
36 0 : static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len,
37 : afi_t afi)
38 : {
39 0 : uint32_t offset = 0;
40 0 : int type;
41 0 : int ret = 0, error = 0;
42 :
43 0 : while (offset < len-1) {
44 0 : type = nlri_content[offset];
45 0 : offset++;
46 0 : switch (type) {
47 0 : case FLOWSPEC_DEST_PREFIX:
48 : case FLOWSPEC_SRC_PREFIX:
49 0 : ret = bgp_flowspec_ip_address(
50 : BGP_FLOWSPEC_VALIDATE_ONLY,
51 : nlri_content + offset,
52 : len - offset, NULL, &error,
53 : afi, NULL);
54 0 : break;
55 0 : case FLOWSPEC_FLOW_LABEL:
56 0 : if (afi == AFI_IP)
57 : return -1;
58 0 : ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY,
59 : nlri_content + offset,
60 : len - offset, NULL, &error);
61 0 : break;
62 0 : case FLOWSPEC_IP_PROTOCOL:
63 : case FLOWSPEC_PORT:
64 : case FLOWSPEC_DEST_PORT:
65 : case FLOWSPEC_SRC_PORT:
66 : case FLOWSPEC_ICMP_TYPE:
67 : case FLOWSPEC_ICMP_CODE:
68 0 : ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY,
69 : nlri_content + offset,
70 : len - offset, NULL, &error);
71 0 : break;
72 0 : case FLOWSPEC_TCP_FLAGS:
73 : case FLOWSPEC_FRAGMENT:
74 0 : ret = bgp_flowspec_bitmask_decode(
75 : BGP_FLOWSPEC_VALIDATE_ONLY,
76 : nlri_content + offset,
77 : len - offset, NULL, &error);
78 0 : break;
79 0 : case FLOWSPEC_PKT_LEN:
80 : case FLOWSPEC_DSCP:
81 0 : ret = bgp_flowspec_op_decode(
82 : BGP_FLOWSPEC_VALIDATE_ONLY,
83 : nlri_content + offset,
84 : len - offset, NULL, &error);
85 0 : break;
86 0 : default:
87 0 : error = -1;
88 0 : break;
89 : }
90 0 : offset += ret;
91 0 : if (error < 0)
92 : break;
93 : }
94 0 : return error;
95 : }
96 :
97 0 : int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
98 : struct bgp_nlri *packet, int withdraw)
99 : {
100 0 : uint8_t *pnt;
101 0 : uint8_t *lim;
102 0 : afi_t afi;
103 0 : safi_t safi;
104 0 : int psize = 0;
105 0 : struct prefix p;
106 0 : void *temp;
107 :
108 : /* Start processing the NLRI - there may be multiple in the MP_REACH */
109 0 : pnt = packet->nlri;
110 0 : lim = pnt + packet->length;
111 0 : afi = packet->afi;
112 0 : safi = packet->safi;
113 :
114 0 : if (packet->length >= FLOWSPEC_NLRI_SIZELIMIT_EXTENDED) {
115 0 : flog_err(EC_BGP_FLOWSPEC_PACKET,
116 : "BGP flowspec nlri length maximum reached (%u)",
117 : packet->length);
118 0 : return BGP_NLRI_PARSE_ERROR_FLOWSPEC_NLRI_SIZELIMIT;
119 : }
120 :
121 0 : for (; pnt < lim; pnt += psize) {
122 : /* Clear prefix structure. */
123 0 : memset(&p, 0, sizeof(p));
124 :
125 : /* All FlowSpec NLRI begin with length. */
126 0 : if (pnt + 1 > lim)
127 : return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
128 :
129 0 : psize = *pnt++;
130 0 : if (psize >= FLOWSPEC_NLRI_SIZELIMIT) {
131 0 : psize &= 0x0f;
132 0 : psize = psize << 8;
133 0 : psize |= *pnt++;
134 : }
135 : /* When packet overflow occur return immediately. */
136 0 : if (pnt + psize > lim) {
137 0 : flog_err(
138 : EC_BGP_FLOWSPEC_PACKET,
139 : "Flowspec NLRI length inconsistent ( size %u seen)",
140 : psize);
141 0 : return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
142 : }
143 0 : if (bgp_fs_nlri_validate(pnt, psize, afi) < 0) {
144 0 : flog_err(
145 : EC_BGP_FLOWSPEC_PACKET,
146 : "Bad flowspec format or NLRI options not supported");
147 0 : return BGP_NLRI_PARSE_ERROR_FLOWSPEC_BAD_FORMAT;
148 : }
149 0 : p.family = AF_FLOWSPEC;
150 0 : p.prefixlen = 0;
151 : /* Flowspec encoding is in bytes */
152 0 : p.u.prefix_flowspec.prefixlen = psize;
153 0 : p.u.prefix_flowspec.family = afi2family(afi);
154 0 : temp = XCALLOC(MTYPE_TMP, psize);
155 0 : memcpy(temp, pnt, psize);
156 0 : p.u.prefix_flowspec.ptr = (uintptr_t) temp;
157 :
158 0 : if (BGP_DEBUG(flowspec, FLOWSPEC)) {
159 0 : char return_string[BGP_FLOWSPEC_NLRI_STRING_MAX];
160 0 : char local_string[BGP_FLOWSPEC_NLRI_STRING_MAX*2+16];
161 0 : char ec_string[BGP_FLOWSPEC_NLRI_STRING_MAX];
162 0 : char *s = NULL;
163 :
164 0 : bgp_fs_nlri_get_string((unsigned char *)
165 : p.u.prefix_flowspec.ptr,
166 0 : p.u.prefix_flowspec.prefixlen,
167 : return_string,
168 : NLRI_STRING_FORMAT_MIN, NULL,
169 : afi);
170 0 : snprintf(ec_string, sizeof(ec_string),
171 : "EC{none}");
172 0 : if (attr && bgp_attr_get_ecommunity(attr)) {
173 0 : s = ecommunity_ecom2str(
174 : bgp_attr_get_ecommunity(attr),
175 : ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
176 0 : snprintf(ec_string, sizeof(ec_string),
177 : "EC{%s}",
178 : s == NULL ? "none" : s);
179 :
180 0 : if (s)
181 0 : ecommunity_strfree(&s);
182 : }
183 0 : snprintf(local_string, sizeof(local_string),
184 : "FS Rx %s %s %s %s", withdraw ?
185 : "Withdraw":"Update",
186 : afi2str(afi), return_string,
187 : attr != NULL ? ec_string : "");
188 0 : zlog_info("%s", local_string);
189 : }
190 : /* Process the route. */
191 0 : if (!withdraw)
192 0 : bgp_update(peer, &p, 0, attr, afi, safi,
193 : ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
194 : NULL, 0, 0, NULL);
195 : else
196 0 : bgp_withdraw(peer, &p, 0, attr, afi, safi,
197 : ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
198 : NULL, 0, NULL);
199 : }
200 : return BGP_NLRI_PARSE_OK;
201 : }
|