/** * libnl callback function. Does the real parsing of a record returned by NETLINK. This function * parses LINK related packets * * @param obj Pointer to a struct nl_object response * @param arg Pointer to a struct etherinfo element where the parse result will be saved */ static void callback_nl_link(struct nl_object *obj, void *arg) { struct etherinfo *ethi = (struct etherinfo *) arg; struct rtnl_link *link = (struct rtnl_link *) obj; struct nl_addr *addr = rtnl_link_get_addr(link); unsigned int i, len; unsigned char *binaddr; char hwaddr[130], *ptr; if( (ethi == NULL) || (ethi->hwaddress != NULL) || (addr == NULL) ) { return; } binaddr = nl_addr_get_binary_addr(addr); memset(&hwaddr, 0, 130); len = 20; ptr = (char *)&hwaddr; for( i = 0; i < 6; i++ ) { if( i == 0 ) { snprintf(ptr, len, "%02X", *(binaddr+i)); len -= 2; ptr += 2; } else { snprintf(ptr, len, ":%02X", *(binaddr+i)); len -= 3; ptr += 3; } } SET_STR_VALUE(ethi->hwaddress, hwaddr); }
char *utils_get_mac_addr(char *interface) { int buflen = 20; char *buf = NULL; struct nl_handle *nlh = NULL; struct nl_cache *cache = NULL; struct rtnl_link *link = NULL; struct nl_addr *addr = NULL; if (zstr(interface)) { return NULL; } if (init_handle(&nlh) != 0) { return NULL; } if ((cache = rtnl_link_alloc_cache(nlh)) == NULL) { return NULL; } if ((link = rtnl_link_get_by_name(cache, interface)) == NULL) { goto mac2str_error2; } if ((addr = rtnl_link_get_addr(link)) == NULL) { goto mac2str_error3; } if ((buf = calloc(sizeof(char *), buflen)) == NULL) { goto mac2str_error4; } buf = nl_addr2str(addr, buf, buflen); mac2str_error4: nl_addr_destroy(addr); mac2str_error3: rtnl_link_put(link); mac2str_error2: nl_close(nlh); nl_handle_destroy(nlh); return buf; }
/* * Given an interface name (e.g., eth0), return the MAC address in human * readable format (e.g., 00:11:52:12:D9:A0). Return NULL for no match. */ char *iface_mac2str(char *ifname) { int buflen = 20; char *buf = NULL; struct nl_handle *handle = NULL; struct nl_cache *cache = NULL; struct rtnl_link *link = NULL; struct nl_addr *addr = NULL; if (ifname == NULL) { return NULL; } if ((cache = _iface_get_link_cache(&handle)) == NULL) { return NULL; } if ((link = rtnl_link_get_by_name(cache, ifname)) == NULL) { goto mac2str_error2; } if ((addr = rtnl_link_get_addr(link)) == NULL) { goto mac2str_error3; } if ((buf = calloc(sizeof(char *), buflen)) == NULL) { goto mac2str_error4; } if ((buf = nl_addr2str(addr, buf, buflen)) != NULL) { char *oldbuf = buf; buf = g_ascii_strup(buf, -1); free(oldbuf); } mac2str_error4: nl_addr_destroy(addr); mac2str_error3: rtnl_link_put(link); mac2str_error2: nl_close(handle); nl_handle_destroy(handle); return buf; }
/* Given an interface's MAC address, return the name (e.g., eth0) in human * readable format. Return NULL for no match */ char *iface_mac2device(char *mac) { struct nl_handle *handle = NULL; struct nl_cache *cache = NULL; struct rtnl_link *link = NULL; struct nl_addr *mac_as_nl_addr = NULL; char *retval = NULL; int i, n; if (mac == NULL) { return NULL; } if ((mac_as_nl_addr = nl_addr_parse(mac, AF_LLC)) == NULL) { return NULL; } if ((cache = _iface_get_link_cache(&handle)) == NULL) { return NULL; } n = nl_cache_nitems(cache); for (i = 0; i <= n; i++) { struct nl_addr *addr; if ((link = rtnl_link_get(cache, i)) == NULL) { continue; } addr = rtnl_link_get_addr(link); if (!nl_addr_cmp(mac_as_nl_addr, addr)) { retval = strdup(rtnl_link_get_name(link)); rtnl_link_put(link); break; } rtnl_link_put(link); } nl_close(handle); nl_handle_destroy(handle); return retval; }
static int get_hwaddr (int ifindex, guint8 *buf) { struct rtnl_link *lk; struct nl_addr *addr; int len; lk = nm_netlink_index_to_rtnl_link (ifindex); if (!lk) return -1; addr = rtnl_link_get_addr (lk); len = nl_addr_get_len (addr); if (len > NM_UTILS_HWADDR_LEN_MAX) len = -1; else memcpy (buf, nl_addr_get_binary_addr (addr), len); rtnl_link_put (lk); return len; }
static void update_hw_address (NMDevice *dev) { NMDeviceWired *self = NM_DEVICE_WIRED (dev); NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); struct rtnl_link *rtnl; struct nl_addr *addr; rtnl = nm_netlink_index_to_rtnl_link (nm_device_get_ip_ifindex (dev)); if (!rtnl) { nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev), "(%s) failed to read hardware address (error %d)", nm_device_get_iface (dev), errno); return; } addr = rtnl_link_get_addr (rtnl); if (!addr) { nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev), "(%s) no hardware address?", nm_device_get_iface (dev)); rtnl_link_put (rtnl); return; } if (nl_addr_get_len (addr) != priv->hw_addr_len) { nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev), "(%s) hardware address is wrong length (expected %d got %d)", nm_device_get_iface (dev), priv->hw_addr_len, nl_addr_get_len (addr)); } else { memcpy (&priv->hw_addr, nl_addr_get_binary_addr (addr), priv->hw_addr_len); } rtnl_link_put (rtnl); }
void nl_bridge::remove_neigh_from_fdb(rtnl_neigh *neigh) { assert(sw); nl_addr *addr = rtnl_neigh_get_lladdr(neigh); if (nl_addr_cmp(rtnl_link_get_addr(bridge), addr) == 0) { // ignore ll addr of bridge on slave return; } // lookup l2_cache as well std::unique_ptr<rtnl_neigh, decltype(&rtnl_neigh_put)> n_lookup( NEIGH_CAST(nl_cache_search(l2_cache.get(), OBJ_CAST(neigh))), rtnl_neigh_put); if (n_lookup) { nl_cache_remove(OBJ_CAST(n_lookup.get())); } const uint32_t port = nl->get_port_id(rtnl_neigh_get_ifindex(neigh)); rofl::caddress_ll mac((uint8_t *)nl_addr_get_binary_addr(addr), nl_addr_get_len(addr)); sw->l2_addr_remove(port, rtnl_neigh_get_vlan(neigh), mac); }
static void nl_obj_input(struct nl_object *obj, void *arg) { struct _obj { NLHDR_COMMON }; struct _obj *o = (struct _obj *)obj; if( o->ce_msgtype == RTM_NEWLINK || o->ce_msgtype == RTM_DELLINK ) { struct rtnl_link *link = (struct rtnl_link *)obj; struct nl_addr *a = rtnl_link_get_addr(link); char buf[123]; nl_addr2str(a, buf, sizeof(buf)); int ifindex = rtnl_link_get_ifindex(link); bool active = rtnl_link_get_flags(link) & IFF_UP; char *iface = rtnl_link_get_name(link); if( o->ce_msgtype == RTM_NEWLINK ) { struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex); if( nla == NULL ) { g_critical("LINK NEW %s %i", iface, ifindex); struct link_addr *nla = link_addr_new(iface, ifindex, active); g_hash_table_insert(nl_runtime.link_addr_cache, &nla->ifindex, nla); }else { g_critical("LINK CHANGE %s %i", iface, ifindex); GHashTableIter iter; gpointer key, value; g_hash_table_iter_init(&iter, nla->addrs); if( active != nla->active ) { while( g_hash_table_iter_next(&iter, &key, &value) ) { struct incident *i; if( active ) { g_critical("LINK UP"); i = incident_new("dionaea.module.nl.addr.new"); }else { g_critical("LINK DOWN"); i = incident_new("dionaea.module.nl.addr.del"); } incident_value_string_set(i, "addr", g_string_new(key)); incident_value_string_set(i, "iface", g_string_new(nla->iface)); incident_value_int_set(i, "scope", nla->ifindex); incident_report(i); incident_free(i); } nla->active = active; } } }else if( o->ce_msgtype == RTM_DELLINK ) { g_critical("LINK DEL %s %i", iface, ifindex); struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex); g_hash_table_remove(nl_runtime.link_addr_cache, &ifindex); link_addr_free(nla); } }else if( o->ce_msgtype == RTM_NEWADDR || o->ce_msgtype == RTM_DELADDR ) { char buf[128]; struct rtnl_addr *addr = (struct rtnl_addr *)obj; struct nl_addr *a = rtnl_addr_get_local(addr); int ifindex = rtnl_addr_get_ifindex(addr); nl_addr2str(a, buf, 128); char *slash; if( (slash = strstr(buf, "/")) != NULL) *slash = '\0'; char *saddr = NULL; struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex); if( !nla ) return; if( o->ce_msgtype == RTM_NEWADDR ) { if( g_hash_table_lookup(nla->addrs, buf) == NULL ) { g_warning("NEW ADDR %s!", buf); saddr = g_strdup(buf); g_hash_table_insert(nla->addrs, saddr, saddr); if( nla->active ) { struct incident *i = incident_new("dionaea.module.nl.addr.new"); incident_value_string_set(i, "addr", g_string_new(saddr)); incident_value_string_set(i, "iface", g_string_new(nla->iface)); incident_value_int_set(i, "scope", nla->ifindex); incident_report(i); incident_free(i); } } }else if( o->ce_msgtype == RTM_DELADDR ) { if( ( saddr = g_hash_table_lookup(nla->addrs, buf) ) != NULL ) { g_warning("DEL ADDR! %s", buf); if( nla->active ) { struct incident *i = incident_new("dionaea.module.nl.addr.del"); incident_value_string_set(i, "addr", g_string_new(saddr)); incident_value_string_set(i, "iface", g_string_new(nla->iface)); incident_value_int_set(i, "scope", nla->ifindex); incident_report(i); incident_free(i); } g_hash_table_remove(nla->addrs, buf); g_free(saddr); } } } /* struct nl_dump_params dp = { .dp_type = NL_DUMP_STATS, .dp_fd = stdout, .dp_dump_msgtype = 1, }; nl_object_dump(obj, &dp); struct nl_dump_params params = { .dp_type = NL_DUMP_LINE, .dp_fd = stdout, .dp_prefix = 1, }; g_debug("addr cache"); nl_cache_dump(nl_runtime.addr_cache, ¶ms); g_debug("arp cache"); nl_cache_dump(nl_runtime.neigh_cache, ¶ms); g_debug("link cache"); nl_cache_dump(nl_runtime.link_cache, ¶ms); */ }
static void handle_class(struct nl_object *obj, void *arg) { struct rtnl_tc *tc = (struct rtnl_tc *) obj; struct element *e; struct rdata *rdata = arg; struct rdata ndata = { .level = rdata->level + 1, }; if (!(e = handle_tc_obj(tc, "class", rdata))) return; ndata.parent = e; if (!strcmp(rtnl_tc_get_kind(tc), "htb")) element_set_txmax(e, rtnl_htb_get_rate((struct rtnl_class *) tc)); find_classes(rtnl_tc_get_handle(tc), &ndata); find_qdiscs(rtnl_tc_get_handle(tc), &ndata); } static void find_qdiscs(uint32_t parent, struct rdata *rdata) { struct rtnl_qdisc *filter; if (!(filter = rtnl_qdisc_alloc())) return; rtnl_tc_set_parent((struct rtnl_tc *) filter, parent); nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter), handle_qdisc, rdata); rtnl_qdisc_put(filter); } static void find_cls(int ifindex, uint32_t parent, struct rdata *rdata) { struct nl_cache *cls_cache; if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0) return; nl_cache_foreach(cls_cache, handle_cls, rdata); nl_cache_free(cls_cache); } static void find_classes(uint32_t parent, struct rdata *rdata) { struct rtnl_class *filter; if (!(filter = rtnl_class_alloc())) return; rtnl_tc_set_parent((struct rtnl_tc *) filter, parent); nl_cache_foreach_filter(class_cache, OBJ_CAST(filter), handle_class, rdata); rtnl_class_put(filter); } static void handle_qdisc(struct nl_object *obj, void *arg) { struct rtnl_tc *tc = (struct rtnl_tc *) obj; struct element *e; struct rdata *rdata = arg; struct rdata ndata = { .level = rdata->level + 1, }; if (!(e = handle_tc_obj(tc, "qdisc", rdata))) return; ndata.parent = e; find_cls(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata); if (rtnl_tc_get_parent(tc) == TC_H_ROOT) { find_cls(rtnl_tc_get_ifindex(tc), TC_H_ROOT, &ndata); find_classes(TC_H_ROOT, &ndata); } find_classes(rtnl_tc_get_handle(tc), &ndata); } static void handle_tc(struct element *e, struct rtnl_link *link) { struct rtnl_qdisc *qdisc; int ifindex = rtnl_link_get_ifindex(link); struct rdata rdata = { .level = 1, .parent = e, }; if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0) return; qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT); if (qdisc) { handle_qdisc(OBJ_CAST(qdisc), &rdata); rtnl_qdisc_put(qdisc); } qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0); if (qdisc) { handle_qdisc(OBJ_CAST(qdisc), &rdata); rtnl_qdisc_put(qdisc); } qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS); if (qdisc) { handle_qdisc(OBJ_CAST(qdisc), &rdata); rtnl_qdisc_put(qdisc); } nl_cache_free(class_cache); } static void update_link_infos(struct element *e, struct rtnl_link *link) { char buf[64]; snprintf(buf, sizeof(buf), "%u", rtnl_link_get_mtu(link)); element_update_info(e, "MTU", buf); rtnl_link_flags2str(rtnl_link_get_flags(link), buf, sizeof(buf)); element_update_info(e, "Flags", buf); rtnl_link_operstate2str(rtnl_link_get_operstate(link), buf, sizeof(buf)); element_update_info(e, "Operstate", buf); snprintf(buf, sizeof(buf), "%u", rtnl_link_get_ifindex(link)); element_update_info(e, "IfIndex", buf); nl_addr2str(rtnl_link_get_addr(link), buf, sizeof(buf)); element_update_info(e, "Address", buf); nl_addr2str(rtnl_link_get_broadcast(link), buf, sizeof(buf)); element_update_info(e, "Broadcast", buf); rtnl_link_mode2str(rtnl_link_get_linkmode(link), buf, sizeof(buf)); element_update_info(e, "Mode", buf); snprintf(buf, sizeof(buf), "%u", rtnl_link_get_txqlen(link)); element_update_info(e, "TXQlen", buf); nl_af2str(rtnl_link_get_family(link), buf, sizeof(buf)); element_update_info(e, "Family", buf); element_update_info(e, "Alias", rtnl_link_get_ifalias(link) ? : ""); element_update_info(e, "Qdisc", rtnl_link_get_qdisc(link) ? : ""); if (rtnl_link_get_link(link)) { snprintf(buf, sizeof(buf), "%u", rtnl_link_get_link(link)); element_update_info(e, "SlaveOfIndex", buf); } } static void do_link(struct nl_object *obj, void *arg) { struct rtnl_link *link = (struct rtnl_link *) obj; struct element *e, *e_parent = NULL; int i, master_ifindex; if (!cfg_show_all && !(rtnl_link_get_flags(link) & IFF_UP)) { /* FIXME: delete element */ return; } /* Check if the interface is a slave of another interface */ if ((master_ifindex = rtnl_link_get_link(link))) { char parent[IFNAMSIZ+1]; rtnl_link_i2name(link_cache, master_ifindex, parent, sizeof(parent)); e_parent = element_lookup(grp, parent, master_ifindex, NULL, 0); } if (!(e = element_lookup(grp, rtnl_link_get_name(link), rtnl_link_get_ifindex(link), e_parent, ELEMENT_CREAT))) return; if (e->e_flags & ELEMENT_FLAG_CREATED) { if (e->e_parent) e->e_level = e->e_parent->e_level + 1; if (element_set_key_attr(e, "bytes", "packets") || element_set_usage_attr(e, "bytes")) BUG(); /* FIXME: Update link infos every 1s or so */ update_link_infos(e, link); e->e_flags &= ~ELEMENT_FLAG_CREATED; } for (i = 0; i < ARRAY_SIZE(link_attrs); i++) { struct attr_map *m = &link_attrs[i]; uint64_t c_rx = 0, c_tx = 0; int flags = 0; if (m->rxid >= 0) { c_rx = rtnl_link_get_stat(link, m->rxid); flags |= UPDATE_FLAG_RX; } if (m->txid >= 0) { c_tx = rtnl_link_get_stat(link, m->txid); flags |= UPDATE_FLAG_TX; } attr_update(e, m->attrid, c_rx, c_tx, flags); } if (!c_notc) handle_tc(e, link); element_notify_update(e, NULL); element_lifesign(e, 1); } static void netlink_read(void) { int err; if ((err = nl_cache_resync(sock, link_cache, NULL, NULL)) < 0) { fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err)); goto disable; } if ((err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) { fprintf(stderr, "Unable to resync qdisc cache: %s\n", nl_geterror(err)); goto disable; } nl_cache_foreach(link_cache, do_link, NULL); return; disable: netlink_ops.m_flags &= ~BMON_MODULE_ENABLED; } static void netlink_shutdown(void) { nl_cache_free(link_cache); nl_cache_free(qdisc_cache); nl_socket_free(sock); }
int main(int argc, char *argv[]) { struct nl_sock *nl_sock; struct nl_cache *link_cache; int ifindex; int ret = 0; int err = 0; if (argc < 2) { printf("%s ip gw on/off tip\n", argv[0]); return -1; } //link if (err = rtnl_route_read_table_names(ROUTE_TABLE)) { printf("failed to read %s. err = %s\n", ROUTE_TABLE, nl_geterror(err)); return -1;; } nl_sock = nl_socket_alloc(); if (NULL == nl_sock) { printf("failed to alloc netlink handler.\n"); return -1; } if (err = nl_connect(nl_sock, NETLINK_ROUTE)) { printf("failed to connect NETLINK_ROUTE. err = %s\n", nl_geterror(err)); ret = -1; goto release_nl; } if (err = rtnl_link_alloc_cache(nl_sock, AF_INET, &link_cache)) { printf("failed to allocate link cache. err = %s\n", nl_geterror(err)); ret = -1; goto release_nl; } ifindex = rtnl_link_name2i(link_cache, NAME); if (0 == ifindex) { printf("%s - failed to find.\n", NAME); ret = -1; goto release_link_cache; } struct rtnl_link * link = rtnl_link_get(link_cache, ifindex); if (link == NULL) { printf("can't get link.\n"); ret = -1; goto release_link_cache; } //rtnl_link_get_by_name struct nl_addr *lladdr = rtnl_link_get_addr(link); if (NULL == lladdr || AF_LLC != nl_addr_get_family(lladdr)) { printf("failed to get MAC\n"); ret = -1; goto release_link; } uint8_t mac_address[ETHER_ADDR_LEN]; memcpy(mac_address, nl_addr_get_binary_addr(lladdr), ETHER_ADDR_LEN); printf("%02X:%02X:%02X:%02X:%02X:%02X\n", mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5]); //addr struct nl_cache * addr_cache; if (err = rtnl_addr_alloc_cache(nl_sock, &addr_cache)) { printf("fail to get addr_cache\n"); ret = -1; goto release_link; } struct rtnl_addr *addr = rtnl_addr_alloc(); rtnl_addr_set_ifindex(addr, ifindex); rtnl_addr_set_family(addr, AF_INET); int prefixlen = 16; nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, get_ip, &prefixlen); nl_cache_free(addr_cache); uint32_t ipaddr = inet_addr(argv[1]); struct nl_addr * local = nl_addr_build(AF_INET, &ipaddr, sizeof(ipaddr)); rtnl_addr_set_local(addr, local); rtnl_addr_set_ifindex(addr, ifindex); rtnl_addr_set_family(addr, AF_INET); rtnl_addr_set_prefixlen(addr, 32); if (!strcmp(argv[2], "on")) { if (err = rtnl_addr_add(nl_sock, addr, 0)) { printf("fail to add addr %s\n", nl_geterror(err)); ret = -1; goto release_addr; } } else { if (err = rtnl_addr_delete(nl_sock, addr, 0)) { printf("fail to del addr %s\n", nl_geterror(err)); ret = -1; goto release_addr; } } //neigh struct nl_cache * neigh_cache; if (err = rtnl_neigh_alloc_cache(nl_sock, &neigh_cache)) { printf("failed to allocate neighbor cache. err = %s\n", nl_geterror(err)); ret = -1; goto release_neigh_cache; } uint32_t gw = inet_addr(argv[3]); struct nl_addr * gw_addr = nl_addr_build(AF_INET, &gw, sizeof(gw)); struct rtnl_neigh * neigh = rtnl_neigh_get(neigh_cache, ifindex, gw_addr); if (neigh) { // It's optional struct nl_addr * lladdr = rtnl_neigh_get_lladdr(neigh); if (lladdr) { uint8_t mac_address[ETHER_ADDR_LEN]; memcpy(mac_address, nl_addr_get_binary_addr(lladdr), ETHER_ADDR_LEN); printf("gw %02X:%02X:%02X:%02X:%02X:%02X\n", mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5]); } } nl_addr_put(gw_addr); //route struct nl_cache *route_cache; if (err = rtnl_route_alloc_cache(nl_sock, AF_INET, 0, &route_cache)) { printf("failed to allocate route cache. err = %s\n", nl_geterror(err)); ret = -1; goto release_neigh_cache; } struct rtnl_route *route = rtnl_route_alloc(); struct nl_addr * taddr; err = nl_addr_parse(argv[4], AF_INET, &taddr); if (err) { printf("failed to get taddr. err = %s\n", nl_geterror(err)); ret = -1; goto release_route_cache; } nl_cache_foreach_filter(route_cache, OBJ_CAST(route), get_route, NULL); /* struct nl_sock *nl_fib_sock; nl_fib_sock = nl_socket_alloc(); if (err = nl_connect(nl_fib_sock, NETLINK_FIB_LOOKUP)) { printf("failed to connect NETLINK_ROUTE. err = %s\n", nl_geterror(err)); ret = -1; goto release_nl; } struct nl_dump_params params = { .dp_fd = stdout, .dp_type = NL_DUMP_DETAILS, }; struct nl_cache *route_cache = flnl_result_alloc_cache(); struct flnl_request *req = flnl_request_alloc(); struct nl_addr * taddr; err = nl_addr_parse(argv[4], AF_INET, &taddr); if (err) { printf("failed to get taddr. err = %s\n", nl_geterror(err)); ret = -1; goto release_route; } int table = RT_TABLE_UNSPEC, scope = RT_SCOPE_UNIVERSE; flnl_request_set_addr(req, taddr); flnl_request_set_table(req, table); flnl_request_set_scope(req, scope); err = flnl_lookup(nl_fib_sock, req, route_cache); if (err) { printf("failed to fib lookup. err = %s\n", nl_geterror(err)); ret = -1; goto release_route_addr; } nl_cache_dump(route_cache, ¶ms); release_route_addr: nl_addr_put(taddr); release_route: nl_cache_free(route_cache); nl_object_put(OBJ_CAST(req)); nl_close(nl_fib_sock); nl_socket_free(nl_fib_sock); */ release_route_cache: nl_cache_free(route_cache); release_neigh_cache: nl_cache_free(neigh_cache); release_addr: nl_addr_put(local); rtnl_addr_put(addr); release_link: rtnl_link_put(link); release_link_cache: nl_cache_free(link_cache); release_nl: nl_close(nl_sock); nl_socket_free(nl_sock); return ret; }
void nl_bridge::update_access_ports(rtnl_link *vxlan_link, rtnl_link *br_link, const uint16_t vid, const uint32_t tunnel_id, const std::deque<rtnl_link *> &bridge_ports, bool add) { // XXX pvid is currently not taken into account for (auto _br_port : bridge_ports) { auto br_port_vlans = rtnl_link_bridge_get_port_vlan(_br_port); if (rtnl_link_get_ifindex(vxlan_link) == rtnl_link_get_ifindex(_br_port)) continue; if (br_port_vlans == nullptr) continue; if (!is_vid_set(vid, br_port_vlans->vlan_bitmap)) continue; bool untagged = is_vid_set(vid, br_port_vlans->untagged_bitmap); int ifindex = rtnl_link_get_ifindex(_br_port); uint32_t pport_no = nl->get_port_id(ifindex); if (pport_no == 0) { LOG(WARNING) << __FUNCTION__ << ": ignoring unknown port " << OBJ_CAST(_br_port); continue; } rtnl_link *link = nl->get_link(rtnl_link_get_ifindex(_br_port), AF_UNSPEC); VLOG(2) << __FUNCTION__ << ": vid=" << vid << ", untagged=" << untagged << ", tunnel_id=" << tunnel_id << ", add=" << add << ", ifindex=" << ifindex << ", pport_no=" << pport_no << ", port: " << OBJ_CAST(_br_port); if (add) { std::string port_name = std::string(rtnl_link_get_name(_br_port)); // this is no longer a normal bridge interface thus we delete all the // bridging entries sw->l2_addr_remove_all_in_vlan(pport_no, vid); vxlan->create_access_port(_br_port, tunnel_id, port_name, pport_no, vid, untagged, nullptr); auto neighs = get_fdb_entries_of_port(_br_port, vid); for (auto n : neighs) { // ignore ll addr of bridge on slave if (nl_addr_cmp(rtnl_link_get_addr(bridge), rtnl_neigh_get_lladdr(n)) == 0) { continue; } VLOG(3) << ": needs to be updated " << OBJ_CAST(n); vxlan->add_l2_neigh(n, link, br_link); } } else { // delete access port and all bridging entries vxlan->delete_access_port(_br_port, pport_no, vid, true); // XXX FIXME check if we have to add the VLANs again (ingress/egress) } } }