Coverage Report

Created: 2025-08-26 06:20

/src/frr/lib/admin_group.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Administrative-group library (RFC3630, RFC5305, RFC5329, RFC7308)
3
 *
4
 * Copyright 2022 Hiroki Shirokura, LINE Corporation
5
 * Copyright 2022 Masakazu Asama
6
 * Copyright 2022 6WIND S.A.
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU General Public License as published by the Free
10
 * Software Foundation; either version 2 of the License, or (at your option)
11
 * any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful, but WITHOUT
14
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16
 * more details.
17
 *
18
 * You should have received a copy of the GNU General Public License along
19
 * with this program; see the file COPYING; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
 */
22
23
#include "admin_group.h"
24
#include "bitfield.h"
25
26
char *admin_group_string(char *out, size_t sz, int indent,
27
       const struct admin_group *ag)
28
0
{
29
0
  bool printed = false;
30
0
  size_t index = 2;
31
0
  int nb_print = 0;
32
33
0
  if (sz < index)
34
0
    return out;
35
36
0
  if (admin_group_explicit_zero(ag)) {
37
0
    snprintf(out, sz, "0x00000000");
38
0
    return out;
39
0
  }
40
41
0
  if (admin_group_zero(ag)) {
42
0
    snprintf(out, sz, "not-set");
43
0
    return out;
44
0
  }
45
46
0
  snprintf(out, sz, "0x");
47
0
  for (ssize_t i = ag->bitmap.m - 1; i >= 0; i--) {
48
0
    if (sz - index <= 0)
49
0
      break;
50
0
    if (ag->bitmap.data[i] == 0 && !printed)
51
0
      continue;
52
0
    if (nb_print != 0 && (nb_print % 4) == 0) {
53
0
      snprintf(&out[index], sz - index, "\n%*s", indent, "");
54
0
      index += indent + 1;
55
0
      snprintf(&out[index], sz - index, "0x%08x ",
56
0
         ag->bitmap.data[i]);
57
0
      index += 2;
58
0
    } else
59
0
      snprintf(&out[index], sz - index, "%08x ",
60
0
         ag->bitmap.data[i]);
61
0
    index += 9;
62
0
    nb_print++;
63
0
    printed = true;
64
0
  }
65
0
  return out;
66
0
}
67
68
char *admin_group_standard_print(char *out, int indent, uint32_t bitmap)
69
0
{
70
0
  bool first = true;
71
0
  int bit, i;
72
0
  size_t ret, line_sz = 0, line_max_sz;
73
74
0
  out[0] = '\0';
75
76
0
  if (bitmap == 0) {
77
0
    snprintf(out, ADMIN_GROUP_PRINT_MAX_SIZE, "not-set");
78
0
    return out;
79
0
  }
80
81
0
  line_max_sz = strlen("0xffffffff ffffffff ffffffff ffffffff");
82
83
0
  for (i = 0; i < 32; i++) {
84
0
    bit = bitmap >> i & 1;
85
0
    if (bit == 0)
86
0
      continue;
87
0
    if (!first) {
88
0
      ret = snprintf(&out[strlen(out)],
89
0
               ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out),
90
0
               ", ");
91
0
      line_sz += ret;
92
0
    }
93
0
    if (line_sz >= line_max_sz) {
94
0
      snprintf(&out[strlen(out)],
95
0
         ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out),
96
0
         "\n%*s", indent, "");
97
98
0
      line_sz = 0;
99
0
    }
100
0
    ret = snprintf(&out[strlen(out)],
101
0
             ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out), "%d",
102
0
             i);
103
0
    line_sz += ret;
104
0
    first = false;
105
0
  }
106
107
0
  return out;
108
0
}
109
110
char *admin_group_print(char *out, int indent, const struct admin_group *ag)
111
0
{
112
0
  bool first = true;
113
0
  uint32_t i;
114
0
  size_t ret, line_sz = 0, line_max_sz;
115
116
0
  out[0] = '\0';
117
118
0
  if (admin_group_size(ag) == 0) {
119
0
    snprintf(out, ADMIN_GROUP_PRINT_MAX_SIZE, "not-set");
120
0
    return out;
121
0
  }
122
123
0
  line_max_sz = strlen("0xffffffff ffffffff ffffffff ffffffff");
124
125
0
  for (i = 0; i < (admin_group_size(ag) * WORD_SIZE); i++) {
126
0
    if (!admin_group_get(ag, i))
127
0
      continue;
128
0
    if (!first) {
129
0
      ret = snprintf(&out[strlen(out)],
130
0
               ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out),
131
0
               ", ");
132
0
      line_sz += ret;
133
0
    }
134
0
    if (line_sz >= line_max_sz) {
135
0
      snprintf(&out[strlen(out)],
136
0
         ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out),
137
0
         "\n%*s", indent, "");
138
139
0
      line_sz = 0;
140
0
    }
141
0
    ret = snprintf(&out[strlen(out)],
142
0
             ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out), "%d",
143
0
             i);
144
0
    line_sz += ret;
145
0
    if (ret >= (ADMIN_GROUP_PRINT_MAX_SIZE - strlen(out))) {
146
0
      out[0] = '\0';
147
0
      return out;
148
0
    }
149
0
    first = false;
150
0
  }
151
152
0
  return out;
153
0
}
154
155
bool admin_group_cmp(const struct admin_group *ag1,
156
         const struct admin_group *ag2)
157
0
{
158
0
  size_t i;
159
160
0
  for (i = 0; i < ag1->bitmap.m || i < ag2->bitmap.m; i++) {
161
0
    if (i >= ag1->bitmap.m) {
162
0
      if (ag2->bitmap.data[i] != 0)
163
0
        return false;
164
0
    } else if (i >= ag2->bitmap.m) {
165
0
      if (ag1->bitmap.data[i] != 0)
166
0
        return false;
167
0
    } else if (memcmp(&ag1->bitmap.data[i], &ag2->bitmap.data[i],
168
0
          sizeof(word_t)) != 0)
169
0
      return false;
170
0
  }
171
172
0
  return true;
173
0
}
174
175
void admin_group_copy(struct admin_group *dst, const struct admin_group *src)
176
0
{
177
0
  assert(bf_is_inited(src->bitmap));
178
0
  if (bf_is_inited(dst->bitmap))
179
0
    bf_free(dst->bitmap);
180
0
  dst->bitmap = bf_copy(src->bitmap);
181
0
}
182
183
void admin_group_init(struct admin_group *ag)
184
0
{
185
0
  assert(!bf_is_inited(ag->bitmap));
186
0
  bf_init(ag->bitmap, WORD_SIZE);
187
0
}
188
189
void admin_group_term(struct admin_group *ag)
190
0
{
191
0
  assert(bf_is_inited(ag->bitmap));
192
0
  bf_free(ag->bitmap);
193
0
}
194
195
word_t admin_group_get_offset(const struct admin_group *ag, size_t oct_offset)
196
0
{
197
0
  assert(bf_is_inited(ag->bitmap));
198
0
  if (ag->bitmap.m < oct_offset)
199
0
    return 0;
200
0
  return ag->bitmap.data[oct_offset];
201
0
}
202
203
static void admin_group_extend(struct admin_group *ag, size_t idx)
204
0
{
205
0
  size_t old_m, m;
206
207
0
  old_m = ag->bitmap.m;
208
0
  m = idx + 1;
209
0
  ag->bitmap.m = m;
210
0
  ag->bitmap.data =
211
0
    XREALLOC(MTYPE_BITFIELD, ag->bitmap.data, m * sizeof(word_t));
212
0
  memset(&ag->bitmap.data[old_m], 0, (m - old_m) * sizeof(word_t));
213
0
}
214
215
void admin_group_set(struct admin_group *ag, size_t pos)
216
0
{
217
0
  size_t idx = bf_index(pos);
218
219
0
  if (idx >= ag->bitmap.m)
220
0
    admin_group_extend(ag, idx);
221
222
0
  ag->bitmap.data[idx] |= 1 << (bf_offset(pos));
223
224
0
  if (idx >= ag->bitmap.n)
225
0
    ag->bitmap.n = idx + 1;
226
0
}
227
228
void admin_group_unset(struct admin_group *ag, size_t pos)
229
0
{
230
0
  if (bf_index(pos) > (ag->bitmap.m - 1))
231
0
    return;
232
0
  bf_release_index(ag->bitmap, pos);
233
0
  ag->bitmap.n = admin_group_size(ag);
234
0
}
235
236
int admin_group_get(const struct admin_group *ag, size_t pos)
237
0
{
238
0
  size_t admin_group_length = admin_group_size(ag);
239
0
  uint32_t oct_offset;
240
0
  size_t idx;
241
242
0
  if (admin_group_length == 0)
243
0
    return 0;
244
245
0
  idx = bf_index(pos);
246
247
0
  if (idx >= admin_group_length)
248
0
    return 0;
249
250
0
  oct_offset = admin_group_get_offset(ag, idx);
251
0
  return oct_offset >> pos & 1;
252
0
}
253
254
void admin_group_bulk_set(struct admin_group *ag, uint32_t bitmap,
255
        size_t oct_offset)
256
0
{
257
258
0
  if (bitmap == 0 && oct_offset == 0) {
259
0
    admin_group_allow_explicit_zero(ag);
260
0
    return;
261
0
  }
262
263
0
  if (oct_offset >= ag->bitmap.m)
264
0
    admin_group_extend(ag, oct_offset);
265
266
0
  ag->bitmap.data[oct_offset] = bitmap;
267
268
0
  if (oct_offset >= ag->bitmap.n)
269
0
    ag->bitmap.n = oct_offset + 1;
270
0
}
271
272
size_t admin_group_size(const struct admin_group *ag)
273
0
{
274
0
  size_t size = 0;
275
276
0
  for (size_t i = 0; i < ag->bitmap.m; i++)
277
0
    if (ag->bitmap.data[i] != 0)
278
0
      size = i + 1;
279
0
  return size;
280
0
}
281
282
size_t admin_group_nb_words(const struct admin_group *ag)
283
0
{
284
0
  return ag->bitmap.n;
285
0
}
286
287
void admin_group_clear(struct admin_group *ag)
288
0
{
289
0
  for (size_t i = 0; i < ag->bitmap.m; i++)
290
0
    ag->bitmap.data[i] = 0;
291
0
  ag->bitmap.n = 0;
292
0
}
293
294
bool admin_group_zero(const struct admin_group *ag)
295
0
{
296
0
  for (size_t i = 0; i < ag->bitmap.m; i++)
297
0
    if (ag->bitmap.data[i] != 0)
298
0
      return false;
299
0
  return true;
300
0
}
301
302
303
bool admin_group_explicit_zero(const struct admin_group *ag)
304
0
{
305
0
  return ag->bitmap.n == 1 && ag->bitmap.data[0] == 0;
306
0
}
307
308
void admin_group_allow_explicit_zero(struct admin_group *ag)
309
0
{
310
0
  if (admin_group_zero(ag))
311
0
    ag->bitmap.n = 1;
312
0
}
313
314
void admin_group_disallow_explicit_zero(struct admin_group *ag)
315
0
{
316
0
  if (admin_group_zero(ag))
317
0
    ag->bitmap.n = 0;
318
0
}
319
320
/* link_std_ag: admin-group in the RFC5305 section 3.1 format
321
 * link_ext_ag: admin-group in the RFC7308 format
322
 * RFC7308 specifies in section 2.3.1 that:
323
 * "If both an AG and EAG are present, a receiving node MUST use the AG
324
 * as the first 32 bits (0-31) of administrative color and use the EAG
325
 * for bits 32 and higher, if present."
326
 */
327
bool admin_group_match_any(const struct admin_group *fad_ag,
328
         const uint32_t *link_std_ag,
329
         const struct admin_group *link_ext_ag)
330
0
{
331
0
  size_t fad_ag_sz, link_ag_sz, i;
332
0
  uint32_t link_ag_bitmap, fad_ag_bitmap;
333
334
0
  assert(fad_ag);
335
336
  /* get the size of admin-groups: i.e. number of used words */
337
0
  fad_ag_sz = admin_group_size(fad_ag);
338
0
  if (link_std_ag && link_ext_ag) {
339
0
    link_ag_sz = admin_group_size(link_ext_ag);
340
0
    if (link_ag_sz == 0)
341
0
      link_ag_sz = 1;
342
0
  } else if (link_std_ag && !link_ext_ag)
343
0
    link_ag_sz = 1;
344
0
  else if (!link_std_ag && link_ext_ag)
345
0
    link_ag_sz = admin_group_size(link_ext_ag);
346
0
  else
347
0
    link_ag_sz = 0;
348
349
0
  for (i = 0; i < fad_ag_sz && i < link_ag_sz; i++) {
350
0
    fad_ag_bitmap = fad_ag->bitmap.data[i];
351
0
    if (i == 0 && link_std_ag)
352
0
      link_ag_bitmap = *link_std_ag;
353
0
    else
354
0
      link_ag_bitmap = link_ext_ag->bitmap.data[i];
355
356
0
    if (fad_ag_bitmap & link_ag_bitmap)
357
0
      return true;
358
0
  }
359
0
  return false;
360
0
}
361
362
/* same comments as admin_group_match_any() */
363
bool admin_group_match_all(const struct admin_group *fad_ag,
364
         const uint32_t *link_std_ag,
365
         const struct admin_group *link_ext_ag)
366
0
{
367
0
  size_t fad_ag_sz, link_ag_sz, i;
368
0
  uint32_t link_ag_bitmap, fad_ag_bitmap;
369
370
0
  assert(fad_ag);
371
372
  /* get the size of admin-groups: i.e. number of used words */
373
0
  fad_ag_sz = admin_group_size(fad_ag);
374
0
  if (link_std_ag && link_ext_ag) {
375
0
    link_ag_sz = admin_group_size(link_ext_ag);
376
0
    if (link_ag_sz == 0)
377
0
      link_ag_sz = 1;
378
0
  } else if (link_std_ag && !link_ext_ag)
379
0
    link_ag_sz = 1;
380
0
  else if (!link_std_ag && link_ext_ag)
381
0
    link_ag_sz = admin_group_size(link_ext_ag);
382
0
  else
383
0
    link_ag_sz = 0;
384
385
0
  if (fad_ag_sz > link_ag_sz)
386
0
    return false;
387
388
0
  for (i = 0; i < fad_ag_sz; i++) {
389
0
    fad_ag_bitmap = fad_ag->bitmap.data[i];
390
0
    if (fad_ag_bitmap == 0)
391
0
      continue;
392
393
0
    if (i == 0 && link_std_ag)
394
0
      link_ag_bitmap = *link_std_ag;
395
0
    else
396
0
      link_ag_bitmap = link_ext_ag->bitmap.data[i];
397
398
0
    if ((fad_ag_bitmap & link_ag_bitmap) != fad_ag_bitmap)
399
0
      return false;
400
0
  }
401
0
  return true;
402
0
}