int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; uint16_t flags; sd_netlink *rtnl; assert(link); assert(link->manager); assert(br_vid_bitmap); assert(br_untagged_bitmap); assert(link->network); /* pvid might not be in br_vid_bitmap yet */ if (pvid) set_bit(pvid, br_vid_bitmap); rtnl = link->manager->rtnl; /* create new RTM message */ r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, link->ifindex); if (r < 0) return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); r = sd_rtnl_message_link_set_family(req, PF_BRIDGE); if (r < 0) return log_link_error_errno(link, r, "Could not set message family: %m"); r = sd_netlink_message_open_container(req, IFLA_AF_SPEC); if (r < 0) return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m"); /* master needs flag self */ if (!link->network->bridge) { flags = BRIDGE_FLAGS_SELF; sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(uint16_t)); } /* add vlan info */ r = append_vlan_info_data(link, req, pvid, br_vid_bitmap, br_untagged_bitmap); if (r < 0) return log_link_error_errno(link, r, "Could not append VLANs: %m"); r = sd_netlink_message_close_container(req); if (r < 0) return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m"); /* send message to the kernel */ r = netlink_call_async(rtnl, NULL, req, set_brvlan_handler, link_netlink_destroy_callback, link); if (r < 0) return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); link_ref(link); return 0; }
static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) { struct ifla_vlan_flags flags = {}; VLan *v; int r; assert(netdev); assert(link); assert(req); v = VLAN(netdev); assert(v); r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_ID attribute: %m"); if (v->gvrp != -1) { flags.mask |= VLAN_FLAG_GVRP; SET_FLAG(flags.flags, VLAN_FLAG_GVRP, v->gvrp); } if (v->mvrp != -1) { flags.mask |= VLAN_FLAG_MVRP; SET_FLAG(flags.flags, VLAN_FLAG_MVRP, v->mvrp); } if (v->reorder_hdr != -1) { flags.mask |= VLAN_FLAG_REORDER_HDR; SET_FLAG(flags.flags, VLAN_FLAG_REORDER_HDR, v->reorder_hdr); } if (v->loose_binding != -1) { flags.mask |= VLAN_FLAG_LOOSE_BINDING; SET_FLAG(flags.flags, VLAN_FLAG_LOOSE_BINDING, v->loose_binding); } r = sd_netlink_message_append_data(req, IFLA_VLAN_FLAGS, &flags, sizeof(struct ifla_vlan_flags)); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_FLAGS attribute: %m"); return 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) { struct bridge_vlan_info br_vlan; int i, j, k, r, done, cnt; uint16_t begin, end; bool untagged = false; assert(link); assert(req); assert(br_vid_bitmap); assert(br_untagged_bitmap); i = cnt = -1; begin = end = UINT16_MAX; for (k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) { unsigned base_bit; uint32_t vid_map = br_vid_bitmap[k]; uint32_t untagged_map = br_untagged_bitmap[k]; base_bit = k * 32; i = -1; done = 0; do { j = find_next_bit(i, vid_map); if (j > 0) { /* first hit of any bit */ if (begin == UINT16_MAX && end == UINT16_MAX) { begin = end = j - 1 + base_bit; untagged = is_bit_set(j - 1, untagged_map); goto next; } /* this bit is a continuation of prior bits */ 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) { end++; goto next; } } else done = 1; if (begin != UINT16_MAX) { cnt++; if (done && k < BRIDGE_VLAN_BITMAP_LEN - 1) break; br_vlan.flags = 0; if (untagged) br_vlan.flags |= BRIDGE_VLAN_INFO_UNTAGGED; if (begin == end) { br_vlan.vid = begin; if (begin == pvid) br_vlan.flags |= BRIDGE_VLAN_INFO_PVID; r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan)); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m"); } else { br_vlan.vid = begin; br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan)); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m"); br_vlan.vid = end; br_vlan.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN; br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_END; r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan)); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m"); } if (done) break; } if (j > 0) { begin = end = j - 1 + base_bit; untagged = is_bit_set(j - 1, untagged_map); } next: i = j; } while (!done); } if (!cnt) return -EINVAL; return cnt; }
int route_configure( Route *route, Link *link, sd_netlink_message_handler_t callback) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL; usec_t lifetime; int r; assert(link); assert(link->manager); assert(link->manager->rtnl); assert(link->ifindex > 0); assert(route->family == AF_INET || route->family == AF_INET6); if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 && set_size(link->routes) >= ROUTES_PER_LINK_MAX) return -E2BIG; r = sd_rtnl_message_new_route(link->manager->rtnl, &req, RTM_NEWROUTE, route->family, route->protocol); if (r < 0) return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m"); if (!in_addr_is_null(route->family, &route->gw)) { if (route->family == AF_INET) r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in); else if (route->family == AF_INET6) r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); r = sd_rtnl_message_route_set_family(req, route->family); if (r < 0) return log_error_errno(r, "Could not set route family: %m"); } if (route->dst_prefixlen) { if (route->family == AF_INET) r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in); else if (route->family == AF_INET6) r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_DST attribute: %m"); r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen); if (r < 0) return log_error_errno(r, "Could not set destination prefix length: %m"); } if (route->src_prefixlen) { if (route->family == AF_INET) r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in); else if (route->family == AF_INET6) r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_SRC attribute: %m"); r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen); if (r < 0) return log_error_errno(r, "Could not set source prefix length: %m"); } if (!in_addr_is_null(route->family, &route->prefsrc)) { if (route->family == AF_INET) r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in); else if (route->family == AF_INET6) r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m"); } r = sd_rtnl_message_route_set_scope(req, route->scope); if (r < 0) return log_error_errno(r, "Could not set scope: %m"); r = sd_rtnl_message_route_set_flags(req, route->flags); if (r < 0) return log_error_errno(r, "Could not set flags: %m"); if (route->table != RT_TABLE_DEFAULT) { if (route->table < 256) { r = sd_rtnl_message_route_set_table(req, route->table); if (r < 0) return log_error_errno(r, "Could not set route table: %m"); } else { r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC); if (r < 0) return log_error_errno(r, "Could not set route table: %m"); /* Table attribute to allow more than 256. */ r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table)); if (r < 0) return log_error_errno(r, "Could not append RTA_TABLE attribute: %m"); } } r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority); if (r < 0) return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m"); r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref); if (r < 0) return log_error_errno(r, "Could not append RTA_PREF attribute: %m"); r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex); if (r < 0) return log_error_errno(r, "Could not append RTA_OIF attribute: %m"); r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL); if (r < 0) return log_error_errno(r, "Could not send rtnetlink message: %m"); link_ref(link); lifetime = route->lifetime; r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route); if (r < 0) return log_error_errno(r, "Could not add route: %m"); /* TODO: drop expiration handling once it can be pushed into the kernel */ route->lifetime = lifetime; if (route->lifetime != USEC_INFINITY) { r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), route->lifetime, 0, route_expire_handler, route); if (r < 0) return log_error_errno(r, "Could not arm expiration timer: %m"); } sd_event_source_unref(route->expire); route->expire = expire; expire = NULL; return 0; }