LCOV - code coverage report
Current view: top level - bpfilter/xlate/nft - nfgroup.c (source / functions) Coverage Total Hit
Test: lcov.out Lines: 98.8 % 86 85
Test Date: 2025-02-26 17:59:59 Functions: 100.0 % 9 9

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-2.0-only */
       2              : /*
       3              :  * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
       4              :  */
       5              : 
       6              : #include "bpfilter/xlate/nft/nfgroup.h"
       7              : 
       8              : #include <linux/netfilter/nfnetlink.h>
       9              : #include <linux/netlink.h>
      10              : 
      11              : #include <errno.h>
      12              : #include <limits.h>
      13              : #include <netlink/msg.h>
      14              : #include <stdbool.h>
      15              : #include <stdint.h>
      16              : #include <stdlib.h>
      17              : #include <string.h>
      18              : 
      19              : #include "bpfilter/xlate/nft/nfmsg.h"
      20              : #include "core/helper.h"
      21              : #include "core/list.h"
      22              : #include "core/response.h"
      23              : 
      24              : struct bf_nfgroup
      25              : {
      26              :     bf_list messages;
      27              : };
      28              : 
      29           20 : int bf_nfgroup_new(struct bf_nfgroup **group)
      30              : {
      31           20 :     bf_assert(group);
      32              : 
      33           19 :     _cleanup_bf_nfgroup_ struct bf_nfgroup *_group = NULL;
      34              : 
      35           19 :     _group = calloc(1, sizeof(*_group));
      36           19 :     if (!_group)
      37              :         return -ENOMEM;
      38              : 
      39           18 :     bf_list_init(&_group->messages, &(bf_list_ops) {
      40              :                                         .free = (bf_list_ops_free)bf_nfmsg_free,
      41              :                                     });
      42              : 
      43           18 :     *group = TAKE_PTR(_group);
      44              : 
      45           18 :     return 0;
      46              : }
      47              : 
      48           15 : int bf_nfgroup_new_from_stream(struct bf_nfgroup **group, struct nlmsghdr *nlh,
      49              :                                size_t length)
      50              : {
      51           15 :     bf_assert(group);
      52           14 :     bf_assert(nlh);
      53           13 :     bf_assert(length < INT_MAX);
      54              :     /* nlmsg_ok() takes an int. length should not be larger than INT_MAX, but
      55              :      * we check anyway to be safe. */
      56              : 
      57           13 :     _cleanup_bf_nfgroup_ struct bf_nfgroup *_group = NULL;
      58           13 :     int len = (int)length;
      59              :     int r;
      60              : 
      61           13 :     r = bf_nfgroup_new(&_group);
      62           13 :     if (r < 0)
      63              :         return r;
      64              : 
      65           71 :     while (nlmsg_ok(nlh, len)) {
      66           58 :         _cleanup_bf_nfmsg_ struct bf_nfmsg *msg = NULL;
      67              : 
      68           58 :         if (nlh->nlmsg_type == NFNL_MSG_BATCH_BEGIN ||
      69              :             nlh->nlmsg_type == NFNL_MSG_BATCH_END) {
      70              :             // Skip batch messages.
      71            0 :             nlh = nlmsg_next(nlh, &len);
      72              :             continue;
      73              :         }
      74              : 
      75           58 :         r = bf_nfmsg_new_from_nlmsghdr(&msg, nlh);
      76           58 :         if (r < 0)
      77              :             return r;
      78              : 
      79           58 :         r = bf_nfgroup_add_message(_group, msg);
      80           58 :         if (r < 0)
      81              :             return r;
      82              : 
      83           58 :         TAKE_PTR(msg);
      84              : 
      85           58 :         nlh = nlmsg_next(nlh, &len);
      86              :     }
      87              : 
      88           13 :     *group = TAKE_PTR(_group);
      89              : 
      90           13 :     return 0;
      91              : }
      92              : 
      93           64 : void bf_nfgroup_free(struct bf_nfgroup **group)
      94              : {
      95           64 :     bf_assert(group);
      96              : 
      97           63 :     if (!*group)
      98              :         return;
      99              : 
     100           18 :     bf_list_clean(&(*group)->messages);
     101           18 :     free(*group);
     102           18 :     *group = NULL;
     103              : }
     104              : 
     105           31 : const bf_list *bf_nfgroup_messages(const struct bf_nfgroup *group)
     106              : {
     107           31 :     bf_assert(group);
     108              : 
     109           30 :     return &group->messages;
     110              : }
     111              : 
     112           13 : size_t bf_nfgroup_size(const struct bf_nfgroup *group)
     113              : {
     114           13 :     bf_assert(group);
     115              : 
     116              :     size_t size = 0;
     117              : 
     118          124 :     bf_list_foreach (&group->messages, msg_node)
     119           55 :         size += bf_nfmsg_len(bf_list_node_get_data(msg_node));
     120              : 
     121           12 :     return size;
     122              : }
     123              : 
     124           11 : bool bf_nfgroup_is_empty(const struct bf_nfgroup *group)
     125              : {
     126           11 :     bf_assert(group);
     127              : 
     128           10 :     return bf_list_is_empty(&group->messages);
     129              : }
     130              : 
     131           80 : int bf_nfgroup_add_message(struct bf_nfgroup *group, struct bf_nfmsg *msg)
     132              : {
     133           80 :     bf_assert(group);
     134           79 :     bf_assert(msg);
     135              : 
     136           78 :     return bf_list_add_tail(&group->messages, msg);
     137              : }
     138              : 
     139           21 : int bf_nfgroup_add_new_message(struct bf_nfgroup *group, struct bf_nfmsg **msg,
     140              :                                uint16_t command, uint16_t seqnr)
     141              : {
     142           21 :     bf_assert(group);
     143              : 
     144           20 :     _cleanup_bf_nfmsg_ struct bf_nfmsg *_msg = NULL;
     145              :     int r;
     146              : 
     147           20 :     r = bf_nfmsg_new(&_msg, command, seqnr);
     148           20 :     if (r < 0)
     149              :         return r;
     150              : 
     151           20 :     r = bf_nfgroup_add_message(group, _msg);
     152           20 :     if (r < 0)
     153              :         return r;
     154              : 
     155           20 :     if (msg)
     156           10 :         *msg = _msg;
     157              : 
     158           20 :     TAKE_PTR(_msg);
     159              : 
     160           20 :     return 0;
     161              : }
     162              : 
     163            4 : int bf_nfgroup_to_response(const struct bf_nfgroup *group,
     164              :                            struct bf_response **resp)
     165              : {
     166            4 :     bf_assert(group);
     167            3 :     bf_assert(resp);
     168              : 
     169            2 :     _cleanup_bf_response_ struct bf_response *_resp = NULL;
     170            2 :     _cleanup_bf_nfmsg_ struct bf_nfmsg *done = NULL;
     171            2 :     size_t size = bf_nfgroup_size(group);
     172            2 :     bool is_multipart = bf_list_size(&group->messages) != 1;
     173              :     void *payload;
     174              :     int r;
     175              : 
     176            2 :     if (is_multipart) {
     177            2 :         r = bf_nfmsg_new_done(&done);
     178            2 :         if (r < 0)
     179              :             return r;
     180              : 
     181            2 :         size += bf_nfmsg_len(done);
     182              :     }
     183              : 
     184            2 :     r = bf_response_new_raw(&_resp, size);
     185            2 :     if (r < 0)
     186              :         return r;
     187              : 
     188            2 :     _resp->type = BF_RES_SUCCESS;
     189            2 :     _resp->data_len = size;
     190            2 :     payload = _resp->data;
     191              : 
     192           23 :     bf_list_foreach (&group->messages, msg_node) {
     193           10 :         struct bf_nfmsg *msg = bf_list_node_get_data(msg_node);
     194              : 
     195           10 :         memcpy(payload, bf_nfmsg_hdr(msg), bf_nfmsg_len(msg));
     196              : 
     197           10 :         if (is_multipart)
     198           10 :             ((struct nlmsghdr *)payload)->nlmsg_flags |= NLM_F_MULTI;
     199              : 
     200           10 :         payload += bf_nfmsg_len(msg);
     201              :     }
     202              : 
     203            2 :     if (is_multipart)
     204            2 :         memcpy(payload, bf_nfmsg_hdr(done), bf_nfmsg_len(done));
     205              : 
     206            2 :     *resp = TAKE_PTR(_resp);
     207              : 
     208            2 :     return 0;
     209              : }
        

Generated by: LCOV version 2.0-1