LCOV - code coverage report
Current view: top level - network - networkd-brvlan.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 151 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 9 0.0 %

          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