Try<Nothing> encode<ingress::Discipline>( const Netlink<struct rtnl_qdisc>& qdisc, const ingress::Discipline& discipline) { int error = rtnl_tc_set_kind(TC_CAST(qdisc.get()), "ingress"); if (error != 0) { return Error( "Failed to set the kind of the queueing discipline: " + string(nl_geterror(error))); } rtnl_tc_set_parent(TC_CAST(qdisc.get()), INGRESS_ROOT.get()); rtnl_tc_set_handle(TC_CAST(qdisc.get()), ingress::HANDLE.get()); return Nothing(); }
static void list_qdiscs(int ifindex, uint32_t parent) { struct nl_cache *qdisc_cache; struct rtnl_qdisc *filter = nl_cli_qdisc_alloc(); qdisc_cache = nl_cli_qdisc_alloc_cache(sock); rtnl_tc_set_ifindex((struct rtnl_tc *) filter, ifindex); rtnl_tc_set_parent((struct rtnl_tc *) filter, parent); params.dp_prefix += NUM_INDENT; nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter), list_qdisc, NULL); params.dp_prefix -= NUM_INDENT; rtnl_qdisc_put(filter); nl_cache_free(qdisc_cache); }
TError TNlHtb::Remove(const TNlLink &link) { struct rtnl_qdisc *qdisc; qdisc = rtnl_qdisc_alloc(); if (!qdisc) return TError(EError::Unknown, std::string("Unable to allocate qdisc object")); rtnl_tc_set_ifindex(TC_CAST(qdisc), link.GetIndex()); rtnl_tc_set_parent(TC_CAST(qdisc), Parent); link.Dump("remove", qdisc); rtnl_qdisc_delete(link.GetSock(), qdisc); rtnl_qdisc_put(qdisc); return TError::Success(); }
TError TNlClass::Create(const TNl &nl) { struct rtnl_class *cls; TError error; int ret; cls = rtnl_class_alloc(); if (!cls) return TError(EError::Unknown, "Cannot allocate rtnl_class object"); rtnl_tc_set_ifindex(TC_CAST(cls), Index); rtnl_tc_set_parent(TC_CAST(cls), Parent); rtnl_tc_set_handle(TC_CAST(cls), Handle); ret = rtnl_tc_set_kind(TC_CAST(cls), Kind.c_str()); if (ret < 0) { error = nl.Error(ret, "Cannot set class kind"); goto free_class; } if (Kind == "htb") { /* must be <= INT32_MAX to prevent overflows in libnl */ uint64_t maxRate = INT32_MAX; /* * HTB doesn't allow 0 rate * FIXME add support for 64-bit rates */ rtnl_htb_set_rate(cls, std::min(Rate ?: 1, maxRate)); rtnl_htb_set_ceil(cls, std::min(Ceil ?: maxRate, maxRate)); rtnl_htb_set_prio(cls, Prio); if (MTU) rtnl_tc_set_mtu(TC_CAST(cls), MTU); if (Quantum) rtnl_htb_set_quantum(cls, Quantum); if (RateBurst) rtnl_htb_set_rbuffer(cls, RateBurst); if (CeilBurst) rtnl_htb_set_cbuffer(cls, CeilBurst); }
TError TNlQdisc::Delete(const TNl &nl) { struct rtnl_qdisc *qdisc; int ret; qdisc = rtnl_qdisc_alloc(); if (!qdisc) return TError(EError::Unknown, std::string("Unable to allocate qdisc object")); rtnl_tc_set_ifindex(TC_CAST(qdisc), Index); rtnl_tc_set_parent(TC_CAST(qdisc), Parent); nl.Dump("remove", qdisc); ret = rtnl_qdisc_delete(nl.GetSock(), qdisc); rtnl_qdisc_put(qdisc); if (ret < 0) return nl.Error(ret, "Cannot remove qdisc"); return TError::Success(); }
/* * function that adds a new ingress qdisc and set the default class for unclassified traffic */ static int qdisc_add_ingress(struct nl_sock *sock, struct rtnl_link *rtnlLink) { struct rtnl_qdisc *qdisc; int err; /* Allocation of a qdisc object */ if (!(qdisc = rtnl_qdisc_alloc())) { printf("Can not allocate Qdisc\n"); return -1; } //rtnl_tc_set_ifindex(TC_CAST(qdisc), master_index); rtnl_tc_set_link(TC_CAST(qdisc), rtnlLink); rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT); //printf("Delete current qdisc\n"); rtnl_qdisc_delete(sock, qdisc); //rtnl_qdisc_put(qdisc); rtnl_tc_set_handle(TC_CAST(qdisc), TC_HANDLE(0xffff, 0)); if ((err = rtnl_tc_set_kind(TC_CAST(qdisc), "ingress"))) { printf("Can not allocate ingress\n"); return -1; } /* Submit request to kernel and wait for response */ if ((err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE))) { printf("Can not allocate ingress Qdisc\n"); return -1; } /* Return the qdisc object to free memory resources */ rtnl_qdisc_put(qdisc); return 0; }
/* * function that creates a new hash table */ static int u32_add_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio, uint32_t htid, uint32_t divisor) { int err; struct rtnl_cls *cls; cls=rtnl_cls_alloc(); if (!(cls)) { printf("Can not allocate classifier\n"); nl_socket_free(sock); exit(1); } rtnl_tc_set_link(TC_CAST(cls), rtnlLink); if ((err = rtnl_tc_set_kind(TC_CAST(cls), "u32"))) { printf("Can not set classifier as u32\n"); return 1; } rtnl_cls_set_prio(cls, prio); rtnl_cls_set_protocol(cls, ETH_P_IP); rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(0xffff, 0)); rtnl_u32_set_handle(cls, htid, 0x0, 0x0); //printf("htid: 0x%X\n", htid); rtnl_u32_set_divisor(cls, divisor); if ((err = rtnl_cls_add(sock, cls, NLM_F_CREATE))) { printf("Can not add classifier: %s\n", nl_geterror(err)); return -1; } rtnl_cls_put(cls); return 0; }
int netem_get_params(char *iface, struct netem_params *params) { struct rtnl_link *link; struct rtnl_qdisc *filter_qdisc; struct rtnl_qdisc *found_qdisc = NULL; int err; int delay, jitter, loss; pthread_mutex_lock(&nl_sock_mutex); if ((err = nl_cache_refill(sock, link_cache)) < 0) { fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err)); goto cleanup; } if ((err = nl_cache_refill(sock, qdisc_cache)) < 0) { fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err)); goto cleanup; } /* filter link by name */ if ((link = rtnl_link_get_by_name(link_cache, iface)) == NULL) { fprintf(stderr, "unknown interface/link name.\n"); goto cleanup; } if (!(filter_qdisc = rtnl_qdisc_alloc())) { /* OOM error */ fprintf(stderr, "couldn't alloc qdisc\n"); goto cleanup_link; } rtnl_tc_set_link(TC_CAST(filter_qdisc), link); rtnl_tc_set_parent(TC_CAST(filter_qdisc), TC_H_ROOT); rtnl_tc_set_kind(TC_CAST(filter_qdisc), "netem"); found_qdisc = (struct rtnl_qdisc *)nl_cache_find( qdisc_cache, OBJ_CAST(filter_qdisc)); if (!found_qdisc) { /* The iface probably doesn't have a netem qdisc at startup. */ goto cleanup_filter_qdisc; } if (0 > (delay = rtnl_netem_get_delay(found_qdisc))) { fprintf(stderr, "couldn't get delay for iface: %s\n", iface); goto cleanup_qdisc; } params->delay = (double)delay / 1000; if (0 > (jitter = rtnl_netem_get_jitter(found_qdisc))) { fprintf(stderr, "couldn't get jitter for iface: %s\n", iface); goto cleanup_qdisc; } params->jitter = (double)jitter / 1000; if (0 > (loss = rtnl_netem_get_loss(found_qdisc))) { fprintf(stderr, "couldn't get loss for iface: %s\n", iface); goto cleanup_qdisc; } /* loss is specified in 10ths of a percent, ie. 1 ==> 0.1% */ params->loss = (int)(loss / (UINT_MAX / 1000)); rtnl_qdisc_put(found_qdisc); rtnl_qdisc_put(filter_qdisc); rtnl_link_put(link); pthread_mutex_unlock(&nl_sock_mutex); return 0; cleanup_qdisc: rtnl_qdisc_put(found_qdisc); cleanup_filter_qdisc: rtnl_qdisc_put(filter_qdisc); cleanup_link: rtnl_link_put(link); cleanup: pthread_mutex_unlock(&nl_sock_mutex); return -1; }
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); }
TError TNlQdisc::Create(const TNl &nl) { TError error = TError::Success(); int ret; struct rtnl_qdisc *qdisc; if (Kind == "") return Delete(nl); qdisc = rtnl_qdisc_alloc(); if (!qdisc) return TError(EError::Unknown, std::string("Unable to allocate qdisc object")); rtnl_tc_set_ifindex(TC_CAST(qdisc), Index); rtnl_tc_set_parent(TC_CAST(qdisc), Parent); rtnl_tc_set_handle(TC_CAST(qdisc), Handle); ret = rtnl_tc_set_kind(TC_CAST(qdisc), Kind.c_str()); if (ret < 0) { error = nl.Error(ret, "Cannot to set qdisc type: " + Kind); goto free_qdisc; } if (Kind == "bfifo" || Kind == "pfifo") { if (Limit) rtnl_qdisc_fifo_set_limit(qdisc, Limit); } if (Kind == "htb") { if (Default) rtnl_htb_set_defcls(qdisc, Default); if (Quantum) rtnl_htb_set_rate2quantum(qdisc, Quantum); } if (Kind == "hfsc") { if (Default) rtnl_qdisc_hfsc_set_defcls(qdisc, Default); } if (Kind == "sfq") { if (Limit) rtnl_sfq_set_limit(qdisc, Limit); if (Quantum) rtnl_sfq_set_quantum(qdisc, Quantum); } if (Kind == "fq_codel") { if (Limit) rtnl_qdisc_fq_codel_set_limit(qdisc, Limit); if (Quantum) rtnl_qdisc_fq_codel_set_quantum(qdisc, Quantum); } nl.Dump("create", qdisc); ret = rtnl_qdisc_add(nl.GetSock(), qdisc, NLM_F_CREATE | NLM_F_REPLACE); if (ret < 0) error = nl.Error(ret, "Cannot create qdisc"); free_qdisc: rtnl_qdisc_put(qdisc); return error; }