LCOV - code coverage report
Current view: top level - network - networkd-brvlan.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 151 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 9 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 166 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : /***
       3                 :            :   Copyright © 2016 BISDN GmbH. All rights reserved.
       4                 :            : ***/
       5                 :            : 
       6                 :            : #include <netinet/in.h>
       7                 :            : #include <linux/if_bridge.h>
       8                 :            : #include <stdbool.h>
       9                 :            : 
      10                 :            : #include "alloc-util.h"
      11                 :            : #include "conf-parser.h"
      12                 :            : #include "netlink-util.h"
      13                 :            : #include "networkd-brvlan.h"
      14                 :            : #include "networkd-link.h"
      15                 :            : #include "networkd-manager.h"
      16                 :            : #include "networkd-network.h"
      17                 :            : #include "parse-util.h"
      18                 :            : #include "vlan-util.h"
      19                 :            : 
      20                 :          0 : static bool is_bit_set(unsigned bit, uint32_t scope) {
      21         [ #  # ]:          0 :         assert(bit < sizeof(scope)*8);
      22                 :          0 :         return scope & (UINT32_C(1) << bit);
      23                 :            : }
      24                 :            : 
      25                 :          0 : static void set_bit(unsigned nr, uint32_t *addr) {
      26         [ #  # ]:          0 :         if (nr < BRIDGE_VLAN_BITMAP_MAX)
      27                 :          0 :                 addr[nr / 32] |= (UINT32_C(1) << (nr % 32));
      28                 :          0 : }
      29                 :            : 
      30                 :          0 : static int find_next_bit(int i, uint32_t x) {
      31                 :            :         int j;
      32                 :            : 
      33         [ #  # ]:          0 :         if (i >= 32)
      34                 :          0 :                 return -1;
      35                 :            : 
      36                 :            :         /* find first bit */
      37         [ #  # ]:          0 :         if (i < 0)
      38                 :          0 :                 return BUILTIN_FFS_U32(x);
      39                 :            : 
      40                 :            :         /* mask off prior finds to get next */
      41                 :          0 :         j = __builtin_ffs(x >> i);
      42         [ #  # ]:          0 :         return j ? j + i : 0;
      43                 :            : }
      44                 :            : 
      45                 :          0 : static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint16_t pvid, const uint32_t *br_vid_bitmap, const uint32_t *br_untagged_bitmap) {
      46                 :            :         struct bridge_vlan_info br_vlan;
      47                 :            :         int i, j, k, r, cnt;
      48                 :            :         uint16_t begin, end;
      49                 :          0 :         bool done, untagged = false;
      50                 :            : 
      51         [ #  # ]:          0 :         assert(link);
      52         [ #  # ]:          0 :         assert(req);
      53         [ #  # ]:          0 :         assert(br_vid_bitmap);
      54         [ #  # ]:          0 :         assert(br_untagged_bitmap);
      55                 :            : 
      56                 :          0 :         cnt = 0;
      57                 :            : 
      58                 :          0 :         begin = end = UINT16_MAX;
      59         [ #  # ]:          0 :         for (k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) {
      60                 :            :                 unsigned base_bit;
      61                 :          0 :                 uint32_t vid_map = br_vid_bitmap[k];
      62                 :          0 :                 uint32_t untagged_map = br_untagged_bitmap[k];
      63                 :            : 
      64                 :          0 :                 base_bit = k * 32;
      65                 :          0 :                 i = -1;
      66                 :          0 :                 done = false;
      67                 :            :                 do {
      68                 :          0 :                         j = find_next_bit(i, vid_map);
      69         [ #  # ]:          0 :                         if (j > 0) {
      70                 :            :                                 /* first hit of any bit */
      71   [ #  #  #  # ]:          0 :                                 if (begin == UINT16_MAX && end == UINT16_MAX) {
      72                 :          0 :                                         begin = end = j - 1 + base_bit;
      73                 :          0 :                                         untagged = is_bit_set(j - 1, untagged_map);
      74                 :          0 :                                         goto next;
      75                 :            :                                 }
      76                 :            : 
      77                 :            :                                 /* this bit is a continuation of prior bits */
      78   [ #  #  #  #  :          0 :                                 if (j - 2 + base_bit == end && untagged == is_bit_set(j - 1, untagged_map) && (uint16_t)j - 1 + base_bit != pvid && (uint16_t)begin != pvid) {
             #  #  #  # ]
      79                 :          0 :                                         end++;
      80                 :          0 :                                         goto next;
      81                 :            :                                 }
      82                 :            :                         } else
      83                 :          0 :                                 done = true;
      84                 :            : 
      85         [ #  # ]:          0 :                         if (begin != UINT16_MAX) {
      86                 :          0 :                                 cnt++;
      87   [ #  #  #  # ]:          0 :                                 if (done && k < BRIDGE_VLAN_BITMAP_LEN - 1)
      88                 :          0 :                                         break;
      89                 :            : 
      90                 :          0 :                                 br_vlan.flags = 0;
      91         [ #  # ]:          0 :                                 if (untagged)
      92                 :          0 :                                         br_vlan.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
      93                 :            : 
      94         [ #  # ]:          0 :                                 if (begin == end) {
      95                 :          0 :                                         br_vlan.vid = begin;
      96                 :            : 
      97         [ #  # ]:          0 :                                         if (begin == pvid)
      98                 :          0 :                                                 br_vlan.flags |= BRIDGE_VLAN_INFO_PVID;
      99                 :            : 
     100                 :          0 :                                         r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
     101         [ #  # ]:          0 :                                         if (r < 0)
     102   [ #  #  #  # ]:          0 :                                                 return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
     103                 :            :                                 } else {
     104                 :          0 :                                         br_vlan.vid = begin;
     105                 :          0 :                                         br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
     106                 :            : 
     107                 :          0 :                                         r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
     108         [ #  # ]:          0 :                                         if (r < 0)
     109   [ #  #  #  # ]:          0 :                                                 return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
     110                 :            : 
     111                 :          0 :                                         br_vlan.vid = end;
     112                 :          0 :                                         br_vlan.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
     113                 :          0 :                                         br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_END;
     114                 :            : 
     115                 :          0 :                                         r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
     116         [ #  # ]:          0 :                                         if (r < 0)
     117   [ #  #  #  # ]:          0 :                                                 return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
     118                 :            :                                 }
     119                 :            : 
     120         [ #  # ]:          0 :                                 if (done)
     121                 :          0 :                                         break;
     122                 :            :                         }
     123         [ #  # ]:          0 :                         if (j > 0) {
     124                 :          0 :                                 begin = end = j - 1 + base_bit;
     125                 :          0 :                                 untagged = is_bit_set(j - 1, untagged_map);
     126                 :            :                         }
     127                 :            : 
     128                 :          0 :                 next:
     129                 :          0 :                         i = j;
     130         [ #  # ]:          0 :                 } while (!done);
     131                 :            :         }
     132                 :            : 
     133         [ #  # ]:          0 :         assert(cnt > 0);
     134                 :          0 :         return cnt;
     135                 :            : }
     136                 :            : 
     137                 :          0 : static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
     138                 :            :         int r;
     139                 :            : 
     140         [ #  # ]:          0 :         assert(link);
     141                 :            : 
     142                 :          0 :         r = sd_netlink_message_get_errno(m);
     143   [ #  #  #  # ]:          0 :         if (r < 0 && r != -EEXIST)
     144   [ #  #  #  # ]:          0 :                 log_link_error_errno(link, r, "Could not add VLAN to bridge port: %m");
     145                 :            : 
     146                 :          0 :         return 1;
     147                 :            : }
     148                 :            : 
     149                 :          0 : int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap) {
     150                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
     151                 :            :         sd_netlink *rtnl;
     152                 :            :         uint16_t flags;
     153                 :            :         int r;
     154                 :            : 
     155         [ #  # ]:          0 :         assert(link);
     156         [ #  # ]:          0 :         assert(link->manager);
     157         [ #  # ]:          0 :         assert(br_vid_bitmap);
     158         [ #  # ]:          0 :         assert(br_untagged_bitmap);
     159         [ #  # ]:          0 :         assert(link->network);
     160                 :            : 
     161                 :            :         /* pvid might not be in br_vid_bitmap yet */
     162         [ #  # ]:          0 :         if (pvid)
     163                 :          0 :                 set_bit(pvid, br_vid_bitmap);
     164                 :            : 
     165                 :          0 :         rtnl = link->manager->rtnl;
     166                 :            : 
     167                 :            :         /* create new RTM message */
     168                 :          0 :         r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, link->ifindex);
     169         [ #  # ]:          0 :         if (r < 0)
     170   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
     171                 :            : 
     172                 :          0 :         r = sd_rtnl_message_link_set_family(req, PF_BRIDGE);
     173         [ #  # ]:          0 :         if (r < 0)
     174   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Could not set message family: %m");
     175                 :            : 
     176                 :          0 :         r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
     177         [ #  # ]:          0 :         if (r < 0)
     178   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
     179                 :            : 
     180                 :            :         /* master needs flag self */
     181         [ #  # ]:          0 :         if (!link->network->bridge) {
     182                 :          0 :                 flags = BRIDGE_FLAGS_SELF;
     183                 :          0 :                 sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(uint16_t));
     184                 :            :         }
     185                 :            : 
     186                 :            :         /* add vlan info */
     187                 :          0 :         r = append_vlan_info_data(link, req, pvid, br_vid_bitmap, br_untagged_bitmap);
     188         [ #  # ]:          0 :         if (r < 0)
     189   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Could not append VLANs: %m");
     190                 :            : 
     191                 :          0 :         r = sd_netlink_message_close_container(req);
     192         [ #  # ]:          0 :         if (r < 0)
     193   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
     194                 :            : 
     195                 :            :         /* send message to the kernel */
     196                 :          0 :         r = netlink_call_async(rtnl, NULL, req, set_brvlan_handler,
     197                 :            :                                link_netlink_destroy_callback, link);
     198         [ #  # ]:          0 :         if (r < 0)
     199   [ #  #  #  # ]:          0 :                 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
     200                 :            : 
     201                 :          0 :         link_ref(link);
     202                 :            : 
     203                 :          0 :         return 0;
     204                 :            : }
     205                 :            : 
     206                 :          0 : int config_parse_brvlan_pvid(const char *unit, const char *filename,
     207                 :            :                              unsigned line, const char *section,
     208                 :            :                              unsigned section_line, const char *lvalue,
     209                 :            :                              int ltype, const char *rvalue, void *data,
     210                 :            :                              void *userdata) {
     211                 :          0 :         Network *network = userdata;
     212                 :            :         uint16_t pvid;
     213                 :            :         int r;
     214                 :            : 
     215                 :          0 :         r = parse_vlanid(rvalue, &pvid);
     216         [ #  # ]:          0 :         if (r < 0)
     217                 :          0 :                 return r;
     218                 :            : 
     219                 :          0 :         network->pvid = pvid;
     220                 :          0 :         network->use_br_vlan = true;
     221                 :            : 
     222                 :          0 :         return 0;
     223                 :            : }
     224                 :            : 
     225                 :          0 : int config_parse_brvlan_vlan(const char *unit, const char *filename,
     226                 :            :                              unsigned line, const char *section,
     227                 :            :                              unsigned section_line, const char *lvalue,
     228                 :            :                              int ltype, const char *rvalue, void *data,
     229                 :            :                              void *userdata) {
     230                 :          0 :         Network *network = userdata;
     231                 :            :         uint16_t vid, vid_end;
     232                 :            :         int r;
     233                 :            : 
     234         [ #  # ]:          0 :         assert(filename);
     235         [ #  # ]:          0 :         assert(section);
     236         [ #  # ]:          0 :         assert(lvalue);
     237         [ #  # ]:          0 :         assert(rvalue);
     238         [ #  # ]:          0 :         assert(data);
     239                 :            : 
     240                 :          0 :         r = parse_vid_range(rvalue, &vid, &vid_end);
     241         [ #  # ]:          0 :         if (r < 0) {
     242         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VLAN, ignoring: %s", rvalue);
     243                 :          0 :                 return 0;
     244                 :            :         }
     245                 :            : 
     246         [ #  # ]:          0 :         for (; vid <= vid_end; vid++)
     247                 :          0 :                 set_bit(vid, network->br_vid_bitmap);
     248                 :            : 
     249                 :          0 :         network->use_br_vlan = true;
     250                 :          0 :         return 0;
     251                 :            : }
     252                 :            : 
     253                 :          0 : int config_parse_brvlan_untagged(const char *unit, const char *filename,
     254                 :            :                                  unsigned line, const char *section,
     255                 :            :                                  unsigned section_line, const char *lvalue,
     256                 :            :                                  int ltype, const char *rvalue, void *data,
     257                 :            :                                  void *userdata) {
     258                 :          0 :         Network *network = userdata;
     259                 :            :         int r;
     260                 :            :         uint16_t vid, vid_end;
     261                 :            : 
     262         [ #  # ]:          0 :         assert(filename);
     263         [ #  # ]:          0 :         assert(section);
     264         [ #  # ]:          0 :         assert(lvalue);
     265         [ #  # ]:          0 :         assert(rvalue);
     266         [ #  # ]:          0 :         assert(data);
     267                 :            : 
     268                 :          0 :         r = parse_vid_range(rvalue, &vid, &vid_end);
     269         [ #  # ]:          0 :         if (r < 0) {
     270         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse VLAN: %s", rvalue);
     271                 :          0 :                 return 0;
     272                 :            :         }
     273                 :            : 
     274         [ #  # ]:          0 :         for (; vid <= vid_end; vid++) {
     275                 :          0 :                 set_bit(vid, network->br_vid_bitmap);
     276                 :          0 :                 set_bit(vid, network->br_untagged_bitmap);
     277                 :            :         }
     278                 :            : 
     279                 :          0 :         network->use_br_vlan = true;
     280                 :          0 :         return 0;
     281                 :            : }

Generated by: LCOV version 1.14