static struct rtattr * find_dump_kind(struct nlmsghdr *n) { struct rtattr *tb1, *tb2[TCA_ACT_MAX+1]; struct rtattr *tb[TCA_ACT_MAX_PRIO + 1]; struct rtattr *rta[TCAA_MAX + 1]; struct rtattr *kind; int min_len = NLMSG_LENGTH(sizeof(struct tcamsg)); int attrlen = n->nlmsg_len - NLMSG_ALIGN(min_len); struct rtattr *attr = (void *) n + NLMSG_ALIGN(min_len); if (rtattr_parse(rta, TCAA_MAX, attr, attrlen) < 0) return NULL; tb1 = rta[TCA_ACT_TAB - 1]; if (tb1 == NULL) return NULL; if (rtattr_parse(tb, TCA_ACT_MAX_PRIO, RTA_DATA(tb1), NLMSG_ALIGN(RTA_PAYLOAD(tb1))) < 0) return NULL; if (tb[0] == NULL) return NULL; if (rtattr_parse(tb2, TCA_ACT_MAX, RTA_DATA(tb[0]), RTA_PAYLOAD(tb[0])) < 0) return NULL; kind = tb2[TCA_ACT_KIND-1]; return kind; }
static int netem_change(struct Qdisc *sch, struct rtattr *opt) { struct netem_sched_data *q = qdisc_priv(sch); struct tc_netem_qopt *qopt; int ret; if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt)) return -EINVAL; qopt = RTA_DATA(opt); ret = set_fifo_limit(q->qdisc, qopt->limit); if (ret) { pr_debug("netem: can't set fifo limit\n"); return ret; } q->latency = qopt->latency; q->jitter = qopt->jitter; q->limit = qopt->limit; q->gap = qopt->gap; q->loss = qopt->loss; q->duplicate = qopt->duplicate; /* Handle nested options after initial queue options. * Should have put all options in nested format but too late now. */ if (RTA_PAYLOAD(opt) > sizeof(*qopt)) { struct rtattr *tb[TCA_NETEM_MAX]; if (rtattr_parse(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(*qopt), RTA_PAYLOAD(opt) - sizeof(*qopt))) return -EINVAL; if (tb[TCA_NETEM_CORR-1]) { ret = get_correlation(sch, tb[TCA_NETEM_CORR-1]); if (ret) return ret; } if (tb[TCA_NETEM_DELAY_DIST-1]) { ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST-1]); if (ret) return ret; } } return 0; }
static int tbf_init(struct Qdisc* sch, struct rtattr *opt) { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; struct rtattr *tb[TCA_TBF_PTAB]; struct tc_tbf_qopt *qopt; MOD_INC_USE_COUNT; if (opt == NULL || rtattr_parse(tb, TCA_TBF_PTAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) || tb[TCA_TBF_PARMS-1] == NULL || RTA_PAYLOAD(tb[TCA_TBF_PARMS-1]) < sizeof(*qopt)) { MOD_DEC_USE_COUNT; return -EINVAL; } qopt = RTA_DATA(tb[TCA_TBF_PARMS-1]); q->R_tab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB-1]); if (q->R_tab == NULL) { MOD_DEC_USE_COUNT; return -EINVAL; } if (qopt->peakrate.rate) { q->P_tab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_PTAB-1]); if (q->P_tab == NULL) { MOD_DEC_USE_COUNT; qdisc_put_rtab(q->R_tab); return -EINVAL; } } PSCHED_GET_TIME(q->t_c); init_timer(&q->wd_timer); q->wd_timer.function = tbf_watchdog; q->wd_timer.data = (unsigned long)sch; q->limit = qopt->limit; q->mtu = qopt->mtu; if (q->mtu == 0) q->mtu = psched_mtu(sch->dev); q->buffer = qopt->buffer; q->tokens = q->buffer; q->ptokens = q->mtu; return 0; }
static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind) { struct ipt_entry_target *t; unsigned h; struct rtattr *tb[TCA_IPT_MAX]; struct tcf_ipt *p; int ret = 0; u32 index = 0; u32 hook = 0; if (NULL == a || NULL == rta || (rtattr_parse(tb, TCA_IPT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0)) { return -1; } if (tb[TCA_IPT_INDEX - 1]) { index = *(u32 *) RTA_DATA(tb[TCA_IPT_INDEX - 1]); DPRINTK("ipt index %d\n", index); } if (index && (p = tcf_hash_lookup(index)) != NULL) { a->priv = (void *) p; spin_lock(&p->lock); if (bind) { p->bindcnt += 1; p->refcnt += 1; } if (ovr) { goto override; } spin_unlock(&p->lock); return ret; }
struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) { unsigned h; struct tcf_police *p; struct rtattr *tb[TCA_POLICE_MAX]; struct tc_police *parm; if (rtattr_parse(tb, TCA_POLICE_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0) return NULL; if (tb[TCA_POLICE_TBF-1] == NULL) return NULL; parm = RTA_DATA(tb[TCA_POLICE_TBF-1]); if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { p->refcnt++; return p; } p = kmalloc(sizeof(*p), GFP_KERNEL); if (p == NULL) return NULL; memset(p, 0, sizeof(*p)); p->refcnt = 1; spin_lock_init(&p->lock); p->stats.lock = &p->lock; if (parm->rate.rate) { if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) goto failure; if (parm->peakrate.rate && (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) goto failure; } if (tb[TCA_POLICE_RESULT-1]) p->result = *(int*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); #ifdef CONFIG_NET_ESTIMATOR if (tb[TCA_POLICE_AVRATE-1]) p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); #endif p->toks = p->burst = parm->burst; p->mtu = parm->mtu; if (p->mtu == 0) { p->mtu = ~0; if (p->R_tab) p->mtu = 255<<p->R_tab->rate.cell_log; } if (p->P_tab) p->ptoks = L2T_P(p, p->mtu); PSCHED_GET_TIME(p->t_c); p->index = parm->index ? : tcf_police_new_index(); p->action = parm->action; #ifdef CONFIG_NET_ESTIMATOR if (est) qdisc_new_estimator(&p->stats, est); #endif h = tcf_police_hash(p->index); write_lock_bh(&police_lock); p->next = tcf_police_ht[h]; tcf_police_ht[h] = p; write_unlock_bh(&police_lock); return p; failure: if (p->R_tab) qdisc_put_rtab(p->R_tab); kfree(p); return NULL; }
static int neigh_update(struct nlmsghdr *nlh) { int err; int len = nlh->nlmsg_len; uint32_t index; char *pifname; char if_name[IF_NAMESIZE]; char buf[512] = {0}; struct ndmsg *ndm; struct rtattr *rta; struct rtattr *tb[NDA_MAX+1]; struct nda_cacheinfo *ci = NULL; struct msg_hdr *hdr; struct arp_add *arp_add; struct arp_del *arp_del; struct route_add *rt_add; struct route_del *rt_del; len -= NLMSG_LENGTH(sizeof(*ndm)); if (len < 0) return -1; ndm = NLMSG_DATA(nlh); hdr = (struct msg_hdr *)buf; if (ndm->ndm_type != RTN_UNICAST) return 0; if (AF_INET != ndm->ndm_family && AF_INET6 != ndm->ndm_family) { fastpath_log_debug("family %d error.\n", ndm->ndm_family); return 0; } index = get_port_map(ndm->ndm_ifindex); if (index >= ROUTE_MAX_LINK) { fastpath_log_debug("ifidx %d not concerned\n", ndm->ndm_ifindex); return 0; } pifname = if_indextoname(ndm->ndm_ifindex, if_name); if (pifname == NULL) { fastpath_log_error("%s:get if name by ifindex:%d err\n", __func__, ndm->ndm_ifindex); return -EIO; } rta = (struct rtattr*)((char*)ndm + NLMSG_ALIGN(sizeof(struct ndmsg))); rtattr_parse(tb, NDA_MAX, rta, len); if (NULL == tb[NDA_DST]) { fastpath_log_error( "nda dst is null.\n"); return -EINVAL; } if (NULL != tb[NDA_CACHEINFO]) { ci = RTA_DATA(tb[NDA_CACHEINFO]); } fastpath_log_debug( "%s: neigh update, family %d, ifidx %d, eif%d, state 0x%02x\n", __func__, ndm->ndm_family, ndm->ndm_ifindex, index, ndm->ndm_state); if (ndm->ndm_state & NUD_FAILED || (ci && (ci->ndm_refcnt == 0))) { hdr->cmd = ROUTE_MSG_DEL_NEIGH; arp_del = (struct arp_del *)hdr->data; arp_del->nh_iface = rte_cpu_to_be_32(index); memcpy(&arp_del->nh_ip, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); err = route_send(hdr); if (err != 0) { fastpath_log_error( "neigh_update: send neigh failed\n", __func__); } hdr->cmd = ROUTE_MSG_DEL_NH; rt_del = (struct route_del *)hdr->data; memcpy(&rt_del->ip, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); rt_del->depth = 32; err = route_send(hdr); if (err != 0) { fastpath_log_error( "neigh_update: send nh failed\n"); } } else /* if (ndm->ndm_state & (NUD_REACHABLE | NUD_PERMANENT)) */ { hdr->cmd = ROUTE_MSG_ADD_NEIGH; arp_add = (struct arp_add *)hdr->data; arp_add->nh_iface = rte_cpu_to_be_32(index); memcpy(&arp_add->nh_ip, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); arp_add->type = rte_cpu_to_be_16(NEIGH_TYPE_REACHABLE); if (NULL != tb[NDA_LLADDR]) { memcpy(&arp_add->nh_arp, (char*)RTA_DATA(tb[NDA_LLADDR]), RTA_PAYLOAD(tb[NDA_LLADDR])); } err = route_send(hdr); if (err != 0) { fastpath_log_error( "neigh_update: send neigh failed\n", __func__); } hdr->cmd = ROUTE_MSG_ADD_NH; rt_add = (struct route_add *)hdr->data; memcpy(&rt_add->ip, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); rt_add->depth = 32; memcpy(&rt_add->nh_ip, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); rt_add->nh_iface = rte_cpu_to_be_32(index); err = route_send(hdr); if (err != 0) { fastpath_log_error( "neigh_update: send nh failed\n"); } } #if 0 else {
static int tbf_change(struct Qdisc* sch, struct rtattr *opt) { int err = -EINVAL; struct tbf_sched_data *q = qdisc_priv(sch); struct rtattr *tb[TCA_TBF_PTAB]; struct tc_tbf_qopt *qopt; struct qdisc_rate_table *rtab = NULL; struct qdisc_rate_table *ptab = NULL; struct Qdisc *child = NULL; int max_size,n; if (rtattr_parse(tb, TCA_TBF_PTAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) || tb[TCA_TBF_PARMS-1] == NULL || RTA_PAYLOAD(tb[TCA_TBF_PARMS-1]) < sizeof(*qopt)) goto done; qopt = RTA_DATA(tb[TCA_TBF_PARMS-1]); rtab = qdisc_get_rtab(&qopt->rate, tb[TCA_TBF_RTAB-1]); if (rtab == NULL) goto done; if (qopt->peakrate.rate) { if (qopt->peakrate.rate > qopt->rate.rate) ptab = qdisc_get_rtab(&qopt->peakrate, tb[TCA_TBF_PTAB-1]); if (ptab == NULL) goto done; } for (n = 0; n < 256; n++) if (rtab->data[n] > qopt->buffer) break; max_size = (n << qopt->rate.cell_log)-1; if (ptab) { int size; for (n = 0; n < 256; n++) if (ptab->data[n] > qopt->mtu) break; size = (n << qopt->peakrate.cell_log)-1; if (size < max_size) max_size = size; } if (max_size < 0) goto done; if (q->qdisc == &noop_qdisc) { if ((child = tbf_create_dflt_qdisc(sch->dev, qopt->limit)) == NULL) goto done; } sch_tree_lock(sch); if (child) q->qdisc = child; q->limit = qopt->limit; q->mtu = qopt->mtu; q->max_size = max_size; q->buffer = qopt->buffer; q->tokens = q->buffer; q->ptokens = q->mtu; rtab = xchg(&q->R_tab, rtab); ptab = xchg(&q->P_tab, ptab); sch_tree_unlock(sch); err = 0; done: if (rtab) qdisc_put_rtab(rtab); if (ptab) qdisc_put_rtab(ptab); return err; }