Coverage Report

Created: 2026-08-11 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/bgpd/bgp_flowspec.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* BGP FlowSpec for packet handling
3
 * Portions:
4
 *     Copyright (C) 2017 ChinaTelecom SDN Group
5
 *     Copyright (C) 2018 6WIND
6
 */
7
8
#include <zebra.h>
9
#include <math.h>
10
11
#include "prefix.h"
12
#include "lib_errors.h"
13
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"
22
23
static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len,
24
        afi_t afi)
25
0
{
26
0
  uint32_t offset = 0;
27
0
  int type;
28
0
  int ret = 0, error = 0;
29
30
0
  while (offset < len-1) {
31
0
    type = nlri_content[offset];
32
0
    offset++;
33
0
    switch (type) {
34
0
    case FLOWSPEC_DEST_PREFIX:
35
0
    case FLOWSPEC_SRC_PREFIX:
36
0
      ret = bgp_flowspec_ip_address(
37
0
            BGP_FLOWSPEC_VALIDATE_ONLY,
38
0
            nlri_content + offset,
39
0
            len - offset, NULL, &error,
40
0
            afi, NULL);
41
0
      break;
42
0
    case FLOWSPEC_FLOW_LABEL:
43
0
      if (afi == AFI_IP)
44
0
        return -1;
45
0
      ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY,
46
0
               nlri_content + offset,
47
0
               len - offset, NULL, &error);
48
0
      break;
49
0
    case FLOWSPEC_IP_PROTOCOL:
50
0
    case FLOWSPEC_PORT:
51
0
    case FLOWSPEC_DEST_PORT:
52
0
    case FLOWSPEC_SRC_PORT:
53
0
    case FLOWSPEC_ICMP_TYPE:
54
0
    case FLOWSPEC_ICMP_CODE:
55
0
      ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY,
56
0
               nlri_content + offset,
57
0
               len - offset, NULL, &error);
58
0
      break;
59
0
    case FLOWSPEC_TCP_FLAGS:
60
0
    case FLOWSPEC_FRAGMENT:
61
0
      ret = bgp_flowspec_bitmask_decode(
62
0
               BGP_FLOWSPEC_VALIDATE_ONLY,
63
0
               nlri_content + offset,
64
0
               len - offset, NULL, &error);
65
0
      break;
66
0
    case FLOWSPEC_PKT_LEN:
67
0
    case FLOWSPEC_DSCP:
68
0
      ret = bgp_flowspec_op_decode(
69
0
            BGP_FLOWSPEC_VALIDATE_ONLY,
70
0
            nlri_content + offset,
71
0
            len - offset, NULL, &error);
72
0
      break;
73
0
    default:
74
0
      error = -1;
75
0
      break;
76
0
    }
77
0
    offset += ret;
78
0
    if (error < 0)
79
0
      break;
80
0
  }
81
0
  return error;
82
0
}
83
84
int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
85
          struct bgp_nlri *packet, bool withdraw)
86
0
{
87
0
  uint8_t *pnt;
88
0
  uint8_t *lim;
89
0
  afi_t afi;
90
0
  safi_t safi;
91
0
  int psize = 0;
92
0
  struct prefix p;
93
0
  void *temp;
94
95
  /* Start processing the NLRI - there may be multiple in the MP_REACH */
96
0
  pnt = packet->nlri;
97
0
  lim = pnt + packet->length;
98
0
  afi = packet->afi;
99
0
  safi = packet->safi;
100
101
  /*
102
   * All other AFI/SAFI's treat no attribute as a implicit
103
   * withdraw.  Flowspec should as well.
104
   */
105
0
  if (!attr)
106
0
    withdraw = true;
107
108
0
  if (packet->length >= FLOWSPEC_NLRI_SIZELIMIT_EXTENDED) {
109
0
    flog_err(EC_BGP_FLOWSPEC_PACKET,
110
0
       "BGP flowspec nlri length maximum reached (%u)",
111
0
       packet->length);
112
0
    return BGP_NLRI_PARSE_ERROR_FLOWSPEC_NLRI_SIZELIMIT;
113
0
  }
114
115
0
  for (; pnt < lim; pnt += psize) {
116
    /* Clear prefix structure. */
117
0
    memset(&p, 0, sizeof(p));
118
119
    /* All FlowSpec NLRI begin with length. */
120
0
    if (pnt + 1 > lim)
121
0
      return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
122
123
0
    psize = *pnt++;
124
0
    if (psize >= FLOWSPEC_NLRI_SIZELIMIT) {
125
0
      psize &= 0x0f;
126
0
      psize = psize << 8;
127
0
      psize |= *pnt++;
128
0
    }
129
    /* When packet overflow occur return immediately. */
130
0
    if (pnt + psize > lim) {
131
0
      flog_err(
132
0
        EC_BGP_FLOWSPEC_PACKET,
133
0
        "Flowspec NLRI length inconsistent ( size %u seen)",
134
0
        psize);
135
0
      return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
136
0
    }
137
138
0
    if (psize == 0) {
139
0
      flog_err(EC_BGP_FLOWSPEC_PACKET,
140
0
         "Flowspec NLRI length 0 which makes no sense");
141
0
      return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
142
0
    }
143
144
0
    if (bgp_fs_nlri_validate(pnt, psize, afi) < 0) {
145
0
      flog_err(
146
0
        EC_BGP_FLOWSPEC_PACKET,
147
0
        "Bad flowspec format or NLRI options not supported");
148
0
      return BGP_NLRI_PARSE_ERROR_FLOWSPEC_BAD_FORMAT;
149
0
    }
150
0
    p.family = AF_FLOWSPEC;
151
0
    p.prefixlen = 0;
152
    /* Flowspec encoding is in bytes */
153
0
    p.u.prefix_flowspec.prefixlen = psize;
154
0
    p.u.prefix_flowspec.family = afi2family(afi);
155
0
    temp = XCALLOC(MTYPE_TMP, psize);
156
0
    memcpy(temp, pnt, psize);
157
0
    p.u.prefix_flowspec.ptr = (uintptr_t) temp;
158
159
0
    if (BGP_DEBUG(flowspec, FLOWSPEC)) {
160
0
      char return_string[BGP_FLOWSPEC_NLRI_STRING_MAX];
161
0
      char local_string[BGP_FLOWSPEC_NLRI_STRING_MAX*2+16];
162
0
      char ec_string[BGP_FLOWSPEC_NLRI_STRING_MAX];
163
0
      char *s = NULL;
164
165
0
      bgp_fs_nlri_get_string((unsigned char *)
166
0
                 p.u.prefix_flowspec.ptr,
167
0
                 p.u.prefix_flowspec.prefixlen,
168
0
                 return_string,
169
0
                 NLRI_STRING_FORMAT_MIN, NULL,
170
0
                 afi);
171
0
      snprintf(ec_string, sizeof(ec_string),
172
0
         "EC{none}");
173
0
      if (attr && bgp_attr_get_ecommunity(attr)) {
174
0
        s = ecommunity_ecom2str(
175
0
          bgp_attr_get_ecommunity(attr),
176
0
          ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
177
0
        snprintf(ec_string, sizeof(ec_string),
178
0
           "EC{%s}",
179
0
          s == NULL ? "none" : s);
180
181
0
        if (s)
182
0
          ecommunity_strfree(&s);
183
0
      }
184
0
      snprintf(local_string, sizeof(local_string),
185
0
         "FS Rx %s %s %s %s", withdraw ?
186
0
         "Withdraw":"Update",
187
0
         afi2str(afi), return_string,
188
0
         attr != NULL ? ec_string : "");
189
0
      zlog_info("%s", local_string);
190
0
    }
191
    /* Process the route. */
192
0
    if (!withdraw) {
193
0
      bgp_update(peer, &p, 0, attr, afi, safi,
194
0
           ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL,
195
0
           NULL, 0, 0, NULL);
196
0
    } else {
197
0
      bgp_withdraw(peer, &p, 0, afi, safi, ZEBRA_ROUTE_BGP,
198
0
             BGP_ROUTE_NORMAL, NULL, NULL, 0, NULL);
199
0
    }
200
201
0
    XFREE(MTYPE_TMP, temp);
202
0
  }
203
0
  return BGP_NLRI_PARSE_OK;
204
0
}