/* 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; }
static int get_gateway_description( sd_netlink *rtnl, sd_hwdb *hwdb, int ifindex, int family, union in_addr_union *gateway, char **gateway_description) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; sd_netlink_message *m; int r; assert(rtnl); assert(ifindex >= 0); assert(family == AF_INET || family == AF_INET6); assert(gateway); assert(gateway_description); r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family); if (r < 0) return r; r = sd_netlink_message_request_dump(req, true); if (r < 0) return r; r = sd_netlink_call(rtnl, req, 0, &reply); if (r < 0) return r; for (m = reply; m; m = sd_netlink_message_next(m)) { union in_addr_union gw = {}; struct ether_addr mac = {}; uint16_t type; int ifi, fam; r = sd_netlink_message_get_errno(m); if (r < 0) { log_error_errno(r, "got error: %m"); continue; } r = sd_netlink_message_get_type(m, &type); if (r < 0) { log_error_errno(r, "could not get type: %m"); continue; } if (type != RTM_NEWNEIGH) { log_error("type is not RTM_NEWNEIGH"); continue; } r = sd_rtnl_message_neigh_get_family(m, &fam); if (r < 0) { log_error_errno(r, "could not get family: %m"); continue; } if (fam != family) { log_error("family is not correct"); continue; } r = sd_rtnl_message_neigh_get_ifindex(m, &ifi); if (r < 0) { log_error_errno(r, "could not get ifindex: %m"); continue; } if (ifindex > 0 && ifi != ifindex) continue; switch (fam) { case AF_INET: r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in); if (r < 0) continue; break; case AF_INET6: r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6); if (r < 0) continue; break; default: continue; } if (!in_addr_equal(fam, &gw, gateway)) continue; r = sd_netlink_message_read_ether_addr(m, NDA_LLADDR, &mac); if (r < 0) continue; r = ieee_oui(hwdb, &mac, gateway_description); if (r < 0) continue; return 0; } return -ENODATA; }