static void get_flags_sync_cb (struct nl_object *obj, void *arg) { GetFlagsInfo *info = arg; /* Ensure this cache item matches our filter */ if (nl_object_match_filter (obj, OBJ_CAST (info->filter)) != 0) info->flags = rtnl_link_get_flags ((struct rtnl_link *) obj); }
// Tests if the flags are set on the link. Returns None if the link is // not found. inline Result<bool> test(const std::string& _link, unsigned int flags) { Result<Netlink<struct rtnl_link>> link = get(_link); if (link.isError()) { return Error(link.error()); } else if (link.isNone()) { return None(); } return flags == (rtnl_link_get_flags(link.get().get()) & flags); }
bool devEthernet::hasLink() { if ( ! _netlinkSocket ) { MOD_ERROR("hasLink() called on uninitialized netlink socket."); return false; } nl_cache* cache; if ( rtnl_link_alloc_cache (_netlinkSocket, AF_UNSPEC, &cache) ) { MOD_ERROR("hasLink() rtnl_link_alloc_cache error: %s", nl_geterror(errno)); return false; } rtnl_link* link = rtnl_link_get(cache, index()); if ( ! link ) { MOD_ERROR("hasLink() rtnl_link_get error: %s", nl_geterror(errno)); nl_cache_free(cache); return false; } // First, check that interface is able to send uint8_t operState = rtnl_link_get_operstate(link); #ifdef DEFINE_DEBUG char buf[100]; rtnl_link_operstate2str (operState, buf, 100); MOD_DEBUG("operState is 0x%x (%s).", operState, buf); #endif bool ret = false; // Next make sure there's a carrier #ifndef IFF_LOWER_UP const int IFF_LOWER_UP = 0x10000; #endif #ifndef IFF_DORMANT const int IFF_DORMANT = 0x20000; #endif if ( operState == OperUp) { unsigned int flags = rtnl_link_get_flags (link); ret = ( ((flags & IFF_LOWER_UP) == IFF_LOWER_UP) && ((flags & IFF_DORMANT) != IFF_DORMANT) ); } rtnl_link_put(link); nl_cache_free(cache); return ret; }
static void iface_mon_handler2(struct nl_object *obj, void *arg) { struct rtnl_link *filter; struct rtnl_link *link_obj; int flags, up; char *ifname; iface_mon_cb cb = (iface_mon_cb)arg; filter = rtnl_link_alloc(); if (!filter) { fprintf(stderr, "error allocating filter\n"); return; } if (nl_object_match_filter (obj, OBJ_CAST (filter)) == 0) { rtnl_link_put(filter); return; } link_obj = (struct rtnl_link *) obj; flags = rtnl_link_get_flags (link_obj); ifname = rtnl_link_get_name(link_obj); /* * You can't bind a PF_PACKET socket to an interface that's not * up, so an interface going down is an "interface should be * removed" indication. * * XXX - what indication, if any, do we get if the interface * *completely goes away*? * * XXX - can we get events if an interface's link-layer or * network addresses change? */ up = (flags & IFF_UP) ? 1 : 0; cb(ifname, up); rtnl_link_put(filter); return; }
static void link_msg_handler (struct nl_object *obj, void *arg) { NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg); struct rtnl_link *filter; struct rtnl_link *link_obj; guint flags; guint ifidx; filter = rtnl_link_alloc (); if (!filter) { log_error_limited (self, NM_NETLINK_MONITOR_ERROR_BAD_ALLOC, _("error processing netlink message: %s"), nl_geterror (ENOMEM)); return; } /* Ensure it's a link object */ if (nl_object_match_filter (obj, OBJ_CAST (filter)) == 0) { rtnl_link_put (filter); return; } link_obj = (struct rtnl_link *) obj; flags = rtnl_link_get_flags (link_obj); ifidx = rtnl_link_get_ifindex (link_obj); nm_log_dbg (LOGD_HW, "netlink link message: iface idx %d flags 0x%X", ifidx, flags); /* IFF_LOWER_UP is the indicator of carrier status since kernel commit * b00055aacdb172c05067612278ba27265fcd05ce in 2.6.17. */ if (flags & IFF_LOWER_UP) g_signal_emit (self, signals[CARRIER_ON], 0, ifidx); else g_signal_emit (self, signals[CARRIER_OFF], 0, ifidx); rtnl_link_put (filter); }
static void _j4status_nl_section_update(J4statusNlSection *self) { if ( self->link == NULL ) return; guint flags; flags = rtnl_link_get_flags(self->link); gchar *value = NULL; J4statusState state = J4STATUS_STATE_NO_STATE; if ( flags & IFF_LOWER_UP ) { if ( ( self->ipv4_addresses == NULL ) && ( self->ipv6_addresses == NULL ) ) { state = J4STATUS_STATE_AVERAGE; value = g_strdup("Connecting"); } else { gchar *addresses; addresses = _j4status_nl_section_get_addresses(self); state = J4STATUS_STATE_GOOD; value = j4status_format_string_replace(self->context->formats.up, _j4status_nl_format_up_callback, addresses); g_free(addresses); } } else if ( flags & (IFF_UP | IFF_RUNNING) ) { state = J4STATUS_STATE_BAD; value = g_strdup("Not connected"); _j4status_nl_section_free_addresses(self); } j4status_section_set_state(self->section, state); j4status_section_set_value(self->section, value); }
// Sets the flags on the link. Returns false if the link is not found. inline Try<bool> set(const std::string& _link, unsigned int flags) { Result<Netlink<struct rtnl_link>> link = get(_link); if (link.isError()) { return Error(link.error()); } else if (link.isNone()) { return false; } // TODO(jieyu): We use ioctl to set the flags because the interfaces // in libnl have some issues with virtual devices. struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); // Get the existing flags and take a bit-wise OR. ifr.ifr_flags = (rtnl_link_get_flags(link.get().get()) | flags); strncpy(ifr.ifr_name, _link.c_str(), IFNAMSIZ); int fd = ::socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { return ErrnoError(); } if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { if (errno == ENODEV) { os::close(fd); return false; } else { // Save the error string as os::close may overwrite errno. const std::string message = os::strerror(errno); os::close(fd); return Error(message); } } return true; }
TError TNl::OpenLinks(std::vector<std::shared_ptr<TNlLink>> &links, bool all) { struct nl_cache *cache; int ret; ret = rtnl_link_alloc_cache(GetSock(), AF_UNSPEC, &cache); if (ret < 0) return Error(ret, "Cannot allocate link cache"); for (auto obj = nl_cache_get_first(cache); obj; obj = nl_cache_get_next(obj)) { auto link = (struct rtnl_link *)obj; if (!all && ((rtnl_link_get_flags(link) & (IFF_LOOPBACK | IFF_RUNNING)) != IFF_RUNNING)) continue; auto l = std::make_shared<TNlLink>(shared_from_this(), link); links.push_back(l); } nl_cache_free(cache); return TError::Success(); }
/* * Called by nl_cache_mngr_data_ready if a link object changed. * * Sends a port status message to the controller. */ static void link_change_cb(struct nl_cache *cache, struct nl_object *obj, int action, void *arg) { struct rtnl_link *link = (struct rtnl_link *) obj; const char *ifname = rtnl_link_get_name(link); int ifflags = rtnl_link_get_flags(link); /* * Ignore additions/deletions, already handled by * ind_ovs_handle_vport_multicast. */ if (action != NL_ACT_CHANGE) { return; } /* Ignore interfaces not connected to our datapath. */ struct ind_ovs_port *port = ind_ovs_port_lookup_by_name(ifname); if (port == NULL) { return; } /* Log at INFO only if the interface transitioned between up/down */ if ((ifflags & IFF_UP) && !(port->ifflags & IFF_UP)) { LOG_INFO("Interface %s state changed to up", ifname); } else if (!(ifflags & IFF_UP) && (port->ifflags & IFF_UP)) { LOG_INFO("Interface %s state changed to down", ifname); } LOG_VERBOSE("Sending port status change notification for interface %s", ifname); port->ifflags = ifflags; port_status_notify(port->dp_port_no, OF_PORT_CHANGE_REASON_MODIFY); }
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); */ }
bool TNlLink::IsRunning() const { return rtnl_link_get_flags(Link) & IFF_RUNNING; }
bool TNlLink::IsLoopback() const { return rtnl_link_get_flags(Link) & IFF_LOOPBACK; }
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); }