int address_update(Address *address, Link *link, sd_rtnl_message_handler_t callback) { _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; int r; assert(address); assert(address->family == AF_INET || address->family == AF_INET6); assert(link->ifindex > 0); assert(link->manager); assert(link->manager->rtnl); r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req, link->ifindex, address->family); if (r < 0) return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m"); r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); if (r < 0) return log_error_errno(r, "Could not set prefixlen: %m"); r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT); if (r < 0) return log_error_errno(r, "Could not set flags: %m"); r = sd_rtnl_message_addr_set_scope(req, address->scope); if (r < 0) return log_error_errno(r, "Could not set scope: %m"); if (address->family == AF_INET) r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in); else if (address->family == AF_INET6) r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6); if (r < 0) return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m"); if (address->family == AF_INET) { r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); if (r < 0) return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m"); } if (address->label) { r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label); if (r < 0) return log_error_errno(r, "Could not append IFA_LABEL attribute: %m"); } r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo); if (r < 0) return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m"); r = sd_rtnl_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); return 0; }
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; }
/* send a request to the kernel to add a FDB entry in its static MAC table. */ int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; sd_netlink *rtnl; int r; uint8_t flags; Bridge *bridge; assert(link); assert(link->network); assert(link->manager); assert(fdb_entry); rtnl = link->manager->rtnl; bridge = BRIDGE(link->network->bridge); /* create new RTM message */ r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_NEWNEIGH, link->ifindex, PF_BRIDGE); if (r < 0) return rtnl_log_create_error(r); if (bridge) flags = NTF_MASTER; else flags = NTF_SELF; r = sd_rtnl_message_neigh_set_flags(req, flags); if (r < 0) return rtnl_log_create_error(r); /* only NUD_PERMANENT state supported. */ r = sd_rtnl_message_neigh_set_state(req, NUD_NOARP | NUD_PERMANENT); if (r < 0) return rtnl_log_create_error(r); r = sd_netlink_message_append_ether_addr(req, NDA_LLADDR, fdb_entry->mac_addr); if (r < 0) return rtnl_log_create_error(r); /* VLAN Id is optional. We'll add VLAN Id only if it's specified. */ if (0 != fdb_entry->vlan_id) { r = sd_netlink_message_append_u16(req, NDA_VLAN, fdb_entry->vlan_id); if (r < 0) return rtnl_log_create_error(r); } /* send message to the kernel to update its internal static MAC table. */ r = sd_netlink_call_async(rtnl, NULL, req, set_fdb_handler, link_netlink_destroy_callback, link, 0, __func__); if (r < 0) return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); link_ref(link); return 0; }
int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, sd_netlink_message_handler_t callback) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert(routing_policy_rule); assert(link); assert(link->manager); assert(link->manager->rtnl); assert(link->ifindex > 0); assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6)); r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family); if (r < 0) return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m"); if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from)) { if (routing_policy_rule->family == AF_INET) r = sd_netlink_message_append_in_addr(m, FRA_SRC, &routing_policy_rule->from.in); else r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &routing_policy_rule->from.in6); if (r < 0) return log_error_errno(r, "Could not append FRA_SRC attribute: %m"); r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen); if (r < 0) return log_error_errno(r, "Could not set source prefix length: %m"); } if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to)) { if (routing_policy_rule->family == AF_INET) r = sd_netlink_message_append_in_addr(m, FRA_DST, &routing_policy_rule->to.in); else r = sd_netlink_message_append_in6_addr(m, FRA_DST, &routing_policy_rule->to.in6); if (r < 0) return log_error_errno(r, "Could not append FRA_DST attribute: %m"); r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen); if (r < 0) return log_error_errno(r, "Could not set destination prefix length: %m"); } r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL); if (r < 0) return log_error_errno(r, "Could not send rtnetlink message: %m"); link_ref(link); return 0; }
int address_label_configure( AddressLabel *label, Link *link, sd_netlink_message_handler_t callback, bool update) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; assert(label); assert(link); assert(link->ifindex > 0); assert(link->manager); assert(link->manager->rtnl); r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &req, RTM_NEWADDRLABEL, link->ifindex, AF_INET6); if (r < 0) return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m"); r = sd_rtnl_message_addrlabel_set_prefixlen(req, label->prefixlen); if (r < 0) return log_error_errno(r, "Could not set prefixlen: %m"); r = sd_netlink_message_append_u32(req, IFAL_LABEL, label->label); if (r < 0) return log_error_errno(r, "Could not append IFAL_LABEL attribute: %m"); r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &label->in_addr.in6); if (r < 0) return log_error_errno(r, "Could not append IFA_ADDRESS 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); return 0; }
int address_drop(Address *address, Link *link, sd_rtnl_message_handler_t callback) { _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; int r; assert(address); assert(address->family == AF_INET || address->family == AF_INET6); assert(link); assert(link->ifindex > 0); assert(link->manager); assert(link->manager->rtnl); address_release(address, link); r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR, link->ifindex, address->family); if (r < 0) return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m"); r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); if (r < 0) return log_error_errno(r, "Could not set prefixlen: %m"); if (address->family == AF_INET) r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in); else if (address->family == AF_INET6) r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6); if (r < 0) return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m"); r = sd_rtnl_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); return 0; }
int netdev_create_vxlan(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) { _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; int r; assert(netdev); assert(!(netdev->kind == NETDEV_KIND_VXLAN) || (link && callback)); assert(netdev->ifname); assert(netdev->manager); assert(netdev->manager->rtnl); r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0); if (r < 0) { log_error_netdev(netdev, "Could not allocate RTM_NEWLINK message: %s", strerror(-r)); return r; } r = netdev_fill_vxlan_rtnl_message(netdev, link, m); if(r < 0) return r; r = sd_rtnl_call_async(netdev->manager->rtnl, m, callback, link, 0, NULL); if (r < 0) { log_error_netdev(netdev, "Could not send rtnetlink message: %s", strerror(-r)); return r; } link_ref(link); log_debug_netdev(netdev, "Creating vxlan netdev: %s", netdev_kind_to_string(netdev->kind)); netdev->state = NETDEV_STATE_CREATING; return 0; }
int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; int r; assert(link); assert(link->manager); assert(link->manager->rtnl); assert(link->ifindex > 0); assert(route->family == AF_INET || route->family == AF_INET6); r = sd_rtnl_message_new_route(link->manager->rtnl, &req, RTM_DELROUTE, route->family, route->protocol); if (r < 0) return log_error_errno(r, "Could not create RTM_DELROUTE message: %m"); if (!in_addr_is_null(route->family, &route->in_addr)) { if (route->family == AF_INET) r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in); else if (route->family == AF_INET6) r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); } if (route->dst_prefixlen) { if (route->family == AF_INET) r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in); else if (route->family == AF_INET6) r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.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_addr.in); else if (route->family == AF_INET6) r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_DST 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_addr)) { if (route->family == AF_INET) r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in); else if (route->family == AF_INET6) r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.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_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics); if (r < 0) return log_error_errno(r, "Could not append RTA_PRIORITY 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); return 0; }
int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlink_message_handler_t callback, bool update) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert(rule); assert(link); assert(link->ifindex > 0); assert(link->manager); assert(link->manager->rtnl); r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family); if (r < 0) return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m"); if (!in_addr_is_null(rule->family, &rule->from)) { if (rule->family == AF_INET) r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in); else r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6); if (r < 0) return log_error_errno(r, "Could not append FRA_SRC attribute: %m"); r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen); if (r < 0) return log_error_errno(r, "Could not set source prefix length: %m"); } if (!in_addr_is_null(rule->family, &rule->to)) { if (rule->family == AF_INET) r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in); else r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6); if (r < 0) return log_error_errno(r, "Could not append FRA_DST attribute: %m"); r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen); if (r < 0) return log_error_errno(r, "Could not set destination prefix length: %m"); } r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority); if (r < 0) return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m"); if (rule->tos > 0) { r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos); if (r < 0) return log_error_errno(r, "Could not set ip rule tos: %m"); } if (rule->table < 256) { r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table); if (r < 0) return log_error_errno(r, "Could not set ip rule table: %m"); } else { r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC); if (r < 0) return log_error_errno(r, "Could not set ip rule table: %m"); r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table); if (r < 0) return log_error_errno(r, "Could not append FRA_TABLE attribute: %m"); } if (rule->fwmark > 0) { r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark); if (r < 0) return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m"); } if (rule->fwmask > 0) { r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask); if (r < 0) return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m"); } if (rule->iif) { r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif); if (r < 0) return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m"); } if (rule->oif) { r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif); if (r < 0) return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m"); } rule->link = link; r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL); if (r < 0) return log_error_errno(r, "Could not send rtnetlink message: %m"); link_ref(link); r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to, rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, NULL); if (r < 0) return log_error_errno(r, "Could not add rule : %m"); return 0; }
int netdev_create_vlan(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) { _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; const char *kind; int r; assert(netdev); assert(netdev->kind == NETDEV_KIND_VLAN); assert(link); assert(callback); assert(netdev->ifname); assert(netdev->manager); assert(netdev->manager->rtnl); r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0); if (r < 0) { log_error_netdev(netdev, "Could not allocate RTM_NEWLINK message: %s", strerror(-r)); return r; } if (link) { r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex); if (r < 0) { log_error_netdev(netdev, "Could not append IFLA_LINK attribute: %s", strerror(-r)); return r; } } r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname); if (r < 0) { log_error_netdev(netdev, "Could not append IFLA_IFNAME attribute: %s", strerror(-r)); return r; } if (netdev->mtu) { r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu); if (r < 0) { log_error_netdev(netdev, "Could not append IFLA_MTU attribute: %s", strerror(-r)); return r; } } if (netdev->mac) { r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac); if (r < 0) { log_error_netdev(netdev, "Colud not append IFLA_ADDRESS attribute: %s", strerror(-r)); return r; } } r = sd_rtnl_message_open_container(req, IFLA_LINKINFO); if (r < 0) { log_error_netdev(netdev, "Could not open IFLA_LINKINFO container: %s", strerror(-r)); return r; } kind = netdev_kind_to_string(netdev->kind); if (!kind) { log_error_netdev(netdev, "Invalid kind"); return -EINVAL; } r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind); if (r < 0) { log_error_netdev(netdev, "Could not open IFLA_INFO_DATA container: %s", strerror(-r)); return r; } if (netdev->vlanid <= VLANID_MAX) { r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid); if (r < 0) { log_error_netdev(netdev, "Could not append IFLA_VLAN_ID attribute: %s", strerror(-r)); return r; } } r = sd_rtnl_message_close_container(req); if (r < 0) { log_error_netdev(netdev, "Could not close IFLA_INFO_DATA container %s", strerror(-r)); return r; } r = sd_rtnl_message_close_container(req); if (r < 0) { log_error_netdev(netdev, "Could not close IFLA_LINKINFO container %s", strerror(-r)); return r; } r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL); if (r < 0) { log_error_netdev(netdev, "Could not send rtnetlink message: %s", strerror(-r)); return r; } link_ref(link); log_debug_netdev(netdev, "creating netdev"); netdev->state = NETDEV_STATE_CREATING; return 0; }
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; }
int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; assert(link); assert(link->manager); assert(link->manager->rtnl); assert(link->ifindex > 0); assert(IN_SET(route->family, AF_INET, AF_INET6)); r = sd_rtnl_message_new_route(link->manager->rtnl, &req, RTM_DELROUTE, route->family, route->protocol); if (r < 0) return log_error_errno(r, "Could not create RTM_DELROUTE 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"); } 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_netlink_message_append_u32(req, RTA_PRIORITY, route->priority); if (r < 0) return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m"); if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) { 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); return 0; }
int netdev_create_tunnel(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) { _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; int r; assert(netdev); assert(netdev->ifname); assert(netdev->manager); assert(netdev->manager->rtnl); assert(link); assert(link->network); assert(link->network->tunnel == netdev); r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0); if (r < 0) { log_error_netdev(netdev, "Could not allocate RTM_NEWLINK message: %s", strerror(-r)); return r; } switch(netdev->kind) { case NETDEV_KIND_IPIP: r = netdev_fill_ipip_rtnl_message(link, m); if(r < 0) return r; break; case NETDEV_KIND_SIT: r = netdev_fill_sit_rtnl_message(link, m); if(r < 0) return r; break; case NETDEV_KIND_VTI: netdev_fill_vti_rtnl_message(link, m); if(r < 0) return r; break; case NETDEV_KIND_GRE: r = netdev_fill_ipgre_rtnl_message(link, m); if(r < 0) return r; break; default: return -ENOTSUP; } r = sd_rtnl_call_async(netdev->manager->rtnl, m, callback, link, 0, NULL); if (r < 0) { log_error_netdev(netdev, "Could not send rtnetlink message: %s", strerror(-r)); return r; } link_ref(link); log_debug_netdev(netdev, "Creating tunnel netdev: %s", netdev_kind_to_string(netdev->kind)); netdev->state = NETDEV_STATE_CREATING; return 0; }