diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /net/sched/sch_api.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'net/sched/sch_api.c')
-rw-r--r-- | net/sched/sch_api.c | 205 |
1 files changed, 120 insertions, 85 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 408eea7086aa..6b8627661c98 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -187,7 +187,7 @@ int unregister_qdisc(struct Qdisc_ops *qops) | |||
187 | int err = -ENOENT; | 187 | int err = -ENOENT; |
188 | 188 | ||
189 | write_lock(&qdisc_mod_lock); | 189 | write_lock(&qdisc_mod_lock); |
190 | for (qp = &qdisc_base; (q=*qp)!=NULL; qp = &q->next) | 190 | for (qp = &qdisc_base; (q = *qp) != NULL; qp = &q->next) |
191 | if (q == qops) | 191 | if (q == qops) |
192 | break; | 192 | break; |
193 | if (q) { | 193 | if (q) { |
@@ -240,7 +240,10 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) | |||
240 | if (q) | 240 | if (q) |
241 | goto out; | 241 | goto out; |
242 | 242 | ||
243 | q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); | 243 | if (dev_ingress_queue(dev)) |
244 | q = qdisc_match_from_root( | ||
245 | dev_ingress_queue(dev)->qdisc_sleeping, | ||
246 | handle); | ||
244 | out: | 247 | out: |
245 | return q; | 248 | return q; |
246 | } | 249 | } |
@@ -318,7 +321,9 @@ void qdisc_put_rtab(struct qdisc_rate_table *tab) | |||
318 | if (!tab || --tab->refcnt) | 321 | if (!tab || --tab->refcnt) |
319 | return; | 322 | return; |
320 | 323 | ||
321 | for (rtabp = &qdisc_rtab_list; (rtab=*rtabp) != NULL; rtabp = &rtab->next) { | 324 | for (rtabp = &qdisc_rtab_list; |
325 | (rtab = *rtabp) != NULL; | ||
326 | rtabp = &rtab->next) { | ||
322 | if (rtab == tab) { | 327 | if (rtab == tab) { |
323 | *rtabp = rtab->next; | 328 | *rtabp = rtab->next; |
324 | kfree(rtab); | 329 | kfree(rtab); |
@@ -360,7 +365,7 @@ static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt) | |||
360 | tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16); | 365 | tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16); |
361 | } | 366 | } |
362 | 367 | ||
363 | if (!s || tsize != s->tsize || (!tab && tsize > 0)) | 368 | if (tsize != s->tsize || (!tab && tsize > 0)) |
364 | return ERR_PTR(-EINVAL); | 369 | return ERR_PTR(-EINVAL); |
365 | 370 | ||
366 | spin_lock(&qdisc_stab_lock); | 371 | spin_lock(&qdisc_stab_lock); |
@@ -393,6 +398,11 @@ static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt) | |||
393 | return stab; | 398 | return stab; |
394 | } | 399 | } |
395 | 400 | ||
401 | static void stab_kfree_rcu(struct rcu_head *head) | ||
402 | { | ||
403 | kfree(container_of(head, struct qdisc_size_table, rcu)); | ||
404 | } | ||
405 | |||
396 | void qdisc_put_stab(struct qdisc_size_table *tab) | 406 | void qdisc_put_stab(struct qdisc_size_table *tab) |
397 | { | 407 | { |
398 | if (!tab) | 408 | if (!tab) |
@@ -402,7 +412,7 @@ void qdisc_put_stab(struct qdisc_size_table *tab) | |||
402 | 412 | ||
403 | if (--tab->refcnt == 0) { | 413 | if (--tab->refcnt == 0) { |
404 | list_del(&tab->list); | 414 | list_del(&tab->list); |
405 | kfree(tab); | 415 | call_rcu_bh(&tab->rcu, stab_kfree_rcu); |
406 | } | 416 | } |
407 | 417 | ||
408 | spin_unlock(&qdisc_stab_lock); | 418 | spin_unlock(&qdisc_stab_lock); |
@@ -425,7 +435,7 @@ nla_put_failure: | |||
425 | return -1; | 435 | return -1; |
426 | } | 436 | } |
427 | 437 | ||
428 | void qdisc_calculate_pkt_len(struct sk_buff *skb, struct qdisc_size_table *stab) | 438 | void __qdisc_calculate_pkt_len(struct sk_buff *skb, const struct qdisc_size_table *stab) |
429 | { | 439 | { |
430 | int pkt_len, slot; | 440 | int pkt_len, slot; |
431 | 441 | ||
@@ -451,14 +461,13 @@ out: | |||
451 | pkt_len = 1; | 461 | pkt_len = 1; |
452 | qdisc_skb_cb(skb)->pkt_len = pkt_len; | 462 | qdisc_skb_cb(skb)->pkt_len = pkt_len; |
453 | } | 463 | } |
454 | EXPORT_SYMBOL(qdisc_calculate_pkt_len); | 464 | EXPORT_SYMBOL(__qdisc_calculate_pkt_len); |
455 | 465 | ||
456 | void qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc) | 466 | void qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc) |
457 | { | 467 | { |
458 | if (!(qdisc->flags & TCQ_F_WARN_NONWC)) { | 468 | if (!(qdisc->flags & TCQ_F_WARN_NONWC)) { |
459 | printk(KERN_WARNING | 469 | pr_warn("%s: %s qdisc %X: is non-work-conserving?\n", |
460 | "%s: %s qdisc %X: is non-work-conserving?\n", | 470 | txt, qdisc->ops->id, qdisc->handle >> 16); |
461 | txt, qdisc->ops->id, qdisc->handle >> 16); | ||
462 | qdisc->flags |= TCQ_F_WARN_NONWC; | 471 | qdisc->flags |= TCQ_F_WARN_NONWC; |
463 | } | 472 | } |
464 | } | 473 | } |
@@ -469,7 +478,7 @@ static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) | |||
469 | struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, | 478 | struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, |
470 | timer); | 479 | timer); |
471 | 480 | ||
472 | wd->qdisc->flags &= ~TCQ_F_THROTTLED; | 481 | qdisc_unthrottled(wd->qdisc); |
473 | __netif_schedule(qdisc_root(wd->qdisc)); | 482 | __netif_schedule(qdisc_root(wd->qdisc)); |
474 | 483 | ||
475 | return HRTIMER_NORESTART; | 484 | return HRTIMER_NORESTART; |
@@ -491,7 +500,7 @@ void qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires) | |||
491 | &qdisc_root_sleeping(wd->qdisc)->state)) | 500 | &qdisc_root_sleeping(wd->qdisc)->state)) |
492 | return; | 501 | return; |
493 | 502 | ||
494 | wd->qdisc->flags |= TCQ_F_THROTTLED; | 503 | qdisc_throttled(wd->qdisc); |
495 | time = ktime_set(0, 0); | 504 | time = ktime_set(0, 0); |
496 | time = ktime_add_ns(time, PSCHED_TICKS2NS(expires)); | 505 | time = ktime_add_ns(time, PSCHED_TICKS2NS(expires)); |
497 | hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS); | 506 | hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS); |
@@ -501,7 +510,7 @@ EXPORT_SYMBOL(qdisc_watchdog_schedule); | |||
501 | void qdisc_watchdog_cancel(struct qdisc_watchdog *wd) | 510 | void qdisc_watchdog_cancel(struct qdisc_watchdog *wd) |
502 | { | 511 | { |
503 | hrtimer_cancel(&wd->timer); | 512 | hrtimer_cancel(&wd->timer); |
504 | wd->qdisc->flags &= ~TCQ_F_THROTTLED; | 513 | qdisc_unthrottled(wd->qdisc); |
505 | } | 514 | } |
506 | EXPORT_SYMBOL(qdisc_watchdog_cancel); | 515 | EXPORT_SYMBOL(qdisc_watchdog_cancel); |
507 | 516 | ||
@@ -622,7 +631,7 @@ static u32 qdisc_alloc_handle(struct net_device *dev) | |||
622 | autohandle = TC_H_MAKE(0x80000000U, 0); | 631 | autohandle = TC_H_MAKE(0x80000000U, 0); |
623 | } while (qdisc_lookup(dev, autohandle) && --i > 0); | 632 | } while (qdisc_lookup(dev, autohandle) && --i > 0); |
624 | 633 | ||
625 | return i>0 ? autohandle : 0; | 634 | return i > 0 ? autohandle : 0; |
626 | } | 635 | } |
627 | 636 | ||
628 | void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) | 637 | void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) |
@@ -690,6 +699,8 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, | |||
690 | (new && new->flags & TCQ_F_INGRESS)) { | 699 | (new && new->flags & TCQ_F_INGRESS)) { |
691 | num_q = 1; | 700 | num_q = 1; |
692 | ingress = 1; | 701 | ingress = 1; |
702 | if (!dev_ingress_queue(dev)) | ||
703 | return -ENOENT; | ||
693 | } | 704 | } |
694 | 705 | ||
695 | if (dev->flags & IFF_UP) | 706 | if (dev->flags & IFF_UP) |
@@ -701,7 +712,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, | |||
701 | } | 712 | } |
702 | 713 | ||
703 | for (i = 0; i < num_q; i++) { | 714 | for (i = 0; i < num_q; i++) { |
704 | struct netdev_queue *dev_queue = &dev->rx_queue; | 715 | struct netdev_queue *dev_queue = dev_ingress_queue(dev); |
705 | 716 | ||
706 | if (!ingress) | 717 | if (!ingress) |
707 | dev_queue = netdev_get_tx_queue(dev, i); | 718 | dev_queue = netdev_get_tx_queue(dev, i); |
@@ -829,7 +840,7 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, | |||
829 | err = PTR_ERR(stab); | 840 | err = PTR_ERR(stab); |
830 | goto err_out4; | 841 | goto err_out4; |
831 | } | 842 | } |
832 | sch->stab = stab; | 843 | rcu_assign_pointer(sch->stab, stab); |
833 | } | 844 | } |
834 | if (tca[TCA_RATE]) { | 845 | if (tca[TCA_RATE]) { |
835 | spinlock_t *root_lock; | 846 | spinlock_t *root_lock; |
@@ -869,7 +880,7 @@ err_out4: | |||
869 | * Any broken qdiscs that would require a ops->reset() here? | 880 | * Any broken qdiscs that would require a ops->reset() here? |
870 | * The qdisc was never in action so it shouldn't be necessary. | 881 | * The qdisc was never in action so it shouldn't be necessary. |
871 | */ | 882 | */ |
872 | qdisc_put_stab(sch->stab); | 883 | qdisc_put_stab(rtnl_dereference(sch->stab)); |
873 | if (ops->destroy) | 884 | if (ops->destroy) |
874 | ops->destroy(sch); | 885 | ops->destroy(sch); |
875 | goto err_out3; | 886 | goto err_out3; |
@@ -877,7 +888,7 @@ err_out4: | |||
877 | 888 | ||
878 | static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) | 889 | static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) |
879 | { | 890 | { |
880 | struct qdisc_size_table *stab = NULL; | 891 | struct qdisc_size_table *ostab, *stab = NULL; |
881 | int err = 0; | 892 | int err = 0; |
882 | 893 | ||
883 | if (tca[TCA_OPTIONS]) { | 894 | if (tca[TCA_OPTIONS]) { |
@@ -894,8 +905,9 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) | |||
894 | return PTR_ERR(stab); | 905 | return PTR_ERR(stab); |
895 | } | 906 | } |
896 | 907 | ||
897 | qdisc_put_stab(sch->stab); | 908 | ostab = rtnl_dereference(sch->stab); |
898 | sch->stab = stab; | 909 | rcu_assign_pointer(sch->stab, stab); |
910 | qdisc_put_stab(ostab); | ||
899 | 911 | ||
900 | if (tca[TCA_RATE]) { | 912 | if (tca[TCA_RATE]) { |
901 | /* NB: ignores errors from replace_estimator | 913 | /* NB: ignores errors from replace_estimator |
@@ -910,9 +922,8 @@ out: | |||
910 | return 0; | 922 | return 0; |
911 | } | 923 | } |
912 | 924 | ||
913 | struct check_loop_arg | 925 | struct check_loop_arg { |
914 | { | 926 | struct qdisc_walker w; |
915 | struct qdisc_walker w; | ||
916 | struct Qdisc *p; | 927 | struct Qdisc *p; |
917 | int depth; | 928 | int depth; |
918 | }; | 929 | }; |
@@ -965,7 +976,8 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
965 | struct Qdisc *p = NULL; | 976 | struct Qdisc *p = NULL; |
966 | int err; | 977 | int err; |
967 | 978 | ||
968 | if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL) | 979 | dev = __dev_get_by_index(net, tcm->tcm_ifindex); |
980 | if (!dev) | ||
969 | return -ENODEV; | 981 | return -ENODEV; |
970 | 982 | ||
971 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); | 983 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); |
@@ -975,11 +987,12 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
975 | if (clid) { | 987 | if (clid) { |
976 | if (clid != TC_H_ROOT) { | 988 | if (clid != TC_H_ROOT) { |
977 | if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) { | 989 | if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) { |
978 | if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL) | 990 | p = qdisc_lookup(dev, TC_H_MAJ(clid)); |
991 | if (!p) | ||
979 | return -ENOENT; | 992 | return -ENOENT; |
980 | q = qdisc_leaf(p, clid); | 993 | q = qdisc_leaf(p, clid); |
981 | } else { /* ingress */ | 994 | } else if (dev_ingress_queue(dev)) { |
982 | q = dev->rx_queue.qdisc_sleeping; | 995 | q = dev_ingress_queue(dev)->qdisc_sleeping; |
983 | } | 996 | } |
984 | } else { | 997 | } else { |
985 | q = dev->qdisc; | 998 | q = dev->qdisc; |
@@ -990,7 +1003,8 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
990 | if (tcm->tcm_handle && q->handle != tcm->tcm_handle) | 1003 | if (tcm->tcm_handle && q->handle != tcm->tcm_handle) |
991 | return -EINVAL; | 1004 | return -EINVAL; |
992 | } else { | 1005 | } else { |
993 | if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL) | 1006 | q = qdisc_lookup(dev, tcm->tcm_handle); |
1007 | if (!q) | ||
994 | return -ENOENT; | 1008 | return -ENOENT; |
995 | } | 1009 | } |
996 | 1010 | ||
@@ -1002,7 +1016,8 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
1002 | return -EINVAL; | 1016 | return -EINVAL; |
1003 | if (q->handle == 0) | 1017 | if (q->handle == 0) |
1004 | return -ENOENT; | 1018 | return -ENOENT; |
1005 | if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0) | 1019 | err = qdisc_graft(dev, p, skb, n, clid, NULL, q); |
1020 | if (err != 0) | ||
1006 | return err; | 1021 | return err; |
1007 | } else { | 1022 | } else { |
1008 | qdisc_notify(net, skb, n, clid, NULL, q); | 1023 | qdisc_notify(net, skb, n, clid, NULL, q); |
@@ -1011,7 +1026,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
1011 | } | 1026 | } |
1012 | 1027 | ||
1013 | /* | 1028 | /* |
1014 | Create/change qdisc. | 1029 | * Create/change qdisc. |
1015 | */ | 1030 | */ |
1016 | 1031 | ||
1017 | static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | 1032 | static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) |
@@ -1030,7 +1045,8 @@ replay: | |||
1030 | clid = tcm->tcm_parent; | 1045 | clid = tcm->tcm_parent; |
1031 | q = p = NULL; | 1046 | q = p = NULL; |
1032 | 1047 | ||
1033 | if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL) | 1048 | dev = __dev_get_by_index(net, tcm->tcm_ifindex); |
1049 | if (!dev) | ||
1034 | return -ENODEV; | 1050 | return -ENODEV; |
1035 | 1051 | ||
1036 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); | 1052 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); |
@@ -1040,11 +1056,12 @@ replay: | |||
1040 | if (clid) { | 1056 | if (clid) { |
1041 | if (clid != TC_H_ROOT) { | 1057 | if (clid != TC_H_ROOT) { |
1042 | if (clid != TC_H_INGRESS) { | 1058 | if (clid != TC_H_INGRESS) { |
1043 | if ((p = qdisc_lookup(dev, TC_H_MAJ(clid))) == NULL) | 1059 | p = qdisc_lookup(dev, TC_H_MAJ(clid)); |
1060 | if (!p) | ||
1044 | return -ENOENT; | 1061 | return -ENOENT; |
1045 | q = qdisc_leaf(p, clid); | 1062 | q = qdisc_leaf(p, clid); |
1046 | } else { /*ingress */ | 1063 | } else if (dev_ingress_queue_create(dev)) { |
1047 | q = dev->rx_queue.qdisc_sleeping; | 1064 | q = dev_ingress_queue(dev)->qdisc_sleeping; |
1048 | } | 1065 | } |
1049 | } else { | 1066 | } else { |
1050 | q = dev->qdisc; | 1067 | q = dev->qdisc; |
@@ -1056,13 +1073,14 @@ replay: | |||
1056 | 1073 | ||
1057 | if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) { | 1074 | if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) { |
1058 | if (tcm->tcm_handle) { | 1075 | if (tcm->tcm_handle) { |
1059 | if (q && !(n->nlmsg_flags&NLM_F_REPLACE)) | 1076 | if (q && !(n->nlmsg_flags & NLM_F_REPLACE)) |
1060 | return -EEXIST; | 1077 | return -EEXIST; |
1061 | if (TC_H_MIN(tcm->tcm_handle)) | 1078 | if (TC_H_MIN(tcm->tcm_handle)) |
1062 | return -EINVAL; | 1079 | return -EINVAL; |
1063 | if ((q = qdisc_lookup(dev, tcm->tcm_handle)) == NULL) | 1080 | q = qdisc_lookup(dev, tcm->tcm_handle); |
1081 | if (!q) | ||
1064 | goto create_n_graft; | 1082 | goto create_n_graft; |
1065 | if (n->nlmsg_flags&NLM_F_EXCL) | 1083 | if (n->nlmsg_flags & NLM_F_EXCL) |
1066 | return -EEXIST; | 1084 | return -EEXIST; |
1067 | if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) | 1085 | if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) |
1068 | return -EINVAL; | 1086 | return -EINVAL; |
@@ -1072,7 +1090,7 @@ replay: | |||
1072 | atomic_inc(&q->refcnt); | 1090 | atomic_inc(&q->refcnt); |
1073 | goto graft; | 1091 | goto graft; |
1074 | } else { | 1092 | } else { |
1075 | if (q == NULL) | 1093 | if (!q) |
1076 | goto create_n_graft; | 1094 | goto create_n_graft; |
1077 | 1095 | ||
1078 | /* This magic test requires explanation. | 1096 | /* This magic test requires explanation. |
@@ -1094,9 +1112,9 @@ replay: | |||
1094 | * For now we select create/graft, if | 1112 | * For now we select create/graft, if |
1095 | * user gave KIND, which does not match existing. | 1113 | * user gave KIND, which does not match existing. |
1096 | */ | 1114 | */ |
1097 | if ((n->nlmsg_flags&NLM_F_CREATE) && | 1115 | if ((n->nlmsg_flags & NLM_F_CREATE) && |
1098 | (n->nlmsg_flags&NLM_F_REPLACE) && | 1116 | (n->nlmsg_flags & NLM_F_REPLACE) && |
1099 | ((n->nlmsg_flags&NLM_F_EXCL) || | 1117 | ((n->nlmsg_flags & NLM_F_EXCL) || |
1100 | (tca[TCA_KIND] && | 1118 | (tca[TCA_KIND] && |
1101 | nla_strcmp(tca[TCA_KIND], q->ops->id)))) | 1119 | nla_strcmp(tca[TCA_KIND], q->ops->id)))) |
1102 | goto create_n_graft; | 1120 | goto create_n_graft; |
@@ -1111,7 +1129,7 @@ replay: | |||
1111 | /* Change qdisc parameters */ | 1129 | /* Change qdisc parameters */ |
1112 | if (q == NULL) | 1130 | if (q == NULL) |
1113 | return -ENOENT; | 1131 | return -ENOENT; |
1114 | if (n->nlmsg_flags&NLM_F_EXCL) | 1132 | if (n->nlmsg_flags & NLM_F_EXCL) |
1115 | return -EEXIST; | 1133 | return -EEXIST; |
1116 | if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) | 1134 | if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) |
1117 | return -EINVAL; | 1135 | return -EINVAL; |
@@ -1121,13 +1139,16 @@ replay: | |||
1121 | return err; | 1139 | return err; |
1122 | 1140 | ||
1123 | create_n_graft: | 1141 | create_n_graft: |
1124 | if (!(n->nlmsg_flags&NLM_F_CREATE)) | 1142 | if (!(n->nlmsg_flags & NLM_F_CREATE)) |
1125 | return -ENOENT; | 1143 | return -ENOENT; |
1126 | if (clid == TC_H_INGRESS) | 1144 | if (clid == TC_H_INGRESS) { |
1127 | q = qdisc_create(dev, &dev->rx_queue, p, | 1145 | if (dev_ingress_queue(dev)) |
1128 | tcm->tcm_parent, tcm->tcm_parent, | 1146 | q = qdisc_create(dev, dev_ingress_queue(dev), p, |
1129 | tca, &err); | 1147 | tcm->tcm_parent, tcm->tcm_parent, |
1130 | else { | 1148 | tca, &err); |
1149 | else | ||
1150 | err = -ENOENT; | ||
1151 | } else { | ||
1131 | struct netdev_queue *dev_queue; | 1152 | struct netdev_queue *dev_queue; |
1132 | 1153 | ||
1133 | if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue) | 1154 | if (p && p->ops->cl_ops && p->ops->cl_ops->select_queue) |
@@ -1165,6 +1186,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, | |||
1165 | struct nlmsghdr *nlh; | 1186 | struct nlmsghdr *nlh; |
1166 | unsigned char *b = skb_tail_pointer(skb); | 1187 | unsigned char *b = skb_tail_pointer(skb); |
1167 | struct gnet_dump d; | 1188 | struct gnet_dump d; |
1189 | struct qdisc_size_table *stab; | ||
1168 | 1190 | ||
1169 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); | 1191 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); |
1170 | tcm = NLMSG_DATA(nlh); | 1192 | tcm = NLMSG_DATA(nlh); |
@@ -1180,7 +1202,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, | |||
1180 | goto nla_put_failure; | 1202 | goto nla_put_failure; |
1181 | q->qstats.qlen = q->q.qlen; | 1203 | q->qstats.qlen = q->q.qlen; |
1182 | 1204 | ||
1183 | if (q->stab && qdisc_dump_stab(skb, q->stab) < 0) | 1205 | stab = rtnl_dereference(q->stab); |
1206 | if (stab && qdisc_dump_stab(skb, stab) < 0) | ||
1184 | goto nla_put_failure; | 1207 | goto nla_put_failure; |
1185 | 1208 | ||
1186 | if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, | 1209 | if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, |
@@ -1224,16 +1247,19 @@ static int qdisc_notify(struct net *net, struct sk_buff *oskb, | |||
1224 | return -ENOBUFS; | 1247 | return -ENOBUFS; |
1225 | 1248 | ||
1226 | if (old && !tc_qdisc_dump_ignore(old)) { | 1249 | if (old && !tc_qdisc_dump_ignore(old)) { |
1227 | if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0) | 1250 | if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, |
1251 | 0, RTM_DELQDISC) < 0) | ||
1228 | goto err_out; | 1252 | goto err_out; |
1229 | } | 1253 | } |
1230 | if (new && !tc_qdisc_dump_ignore(new)) { | 1254 | if (new && !tc_qdisc_dump_ignore(new)) { |
1231 | if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0) | 1255 | if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, |
1256 | old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0) | ||
1232 | goto err_out; | 1257 | goto err_out; |
1233 | } | 1258 | } |
1234 | 1259 | ||
1235 | if (skb->len) | 1260 | if (skb->len) |
1236 | return rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); | 1261 | return rtnetlink_send(skb, net, pid, RTNLGRP_TC, |
1262 | n->nlmsg_flags & NLM_F_ECHO); | ||
1237 | 1263 | ||
1238 | err_out: | 1264 | err_out: |
1239 | kfree_skb(skb); | 1265 | kfree_skb(skb); |
@@ -1265,7 +1291,7 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, | |||
1265 | q_idx++; | 1291 | q_idx++; |
1266 | continue; | 1292 | continue; |
1267 | } | 1293 | } |
1268 | if (!tc_qdisc_dump_ignore(q) && | 1294 | if (!tc_qdisc_dump_ignore(q) && |
1269 | tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, | 1295 | tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, |
1270 | cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) | 1296 | cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) |
1271 | goto done; | 1297 | goto done; |
@@ -1304,8 +1330,10 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) | |||
1304 | if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0) | 1330 | if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0) |
1305 | goto done; | 1331 | goto done; |
1306 | 1332 | ||
1307 | dev_queue = &dev->rx_queue; | 1333 | dev_queue = dev_ingress_queue(dev); |
1308 | if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0) | 1334 | if (dev_queue && |
1335 | tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, | ||
1336 | &q_idx, s_q_idx) < 0) | ||
1309 | goto done; | 1337 | goto done; |
1310 | 1338 | ||
1311 | cont: | 1339 | cont: |
@@ -1344,7 +1372,8 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
1344 | u32 qid = TC_H_MAJ(clid); | 1372 | u32 qid = TC_H_MAJ(clid); |
1345 | int err; | 1373 | int err; |
1346 | 1374 | ||
1347 | if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL) | 1375 | dev = __dev_get_by_index(net, tcm->tcm_ifindex); |
1376 | if (!dev) | ||
1348 | return -ENODEV; | 1377 | return -ENODEV; |
1349 | 1378 | ||
1350 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); | 1379 | err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); |
@@ -1379,9 +1408,9 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
1379 | qid = dev->qdisc->handle; | 1408 | qid = dev->qdisc->handle; |
1380 | 1409 | ||
1381 | /* Now qid is genuine qdisc handle consistent | 1410 | /* Now qid is genuine qdisc handle consistent |
1382 | both with parent and child. | 1411 | * both with parent and child. |
1383 | 1412 | * | |
1384 | TC_H_MAJ(pid) still may be unspecified, complete it now. | 1413 | * TC_H_MAJ(pid) still may be unspecified, complete it now. |
1385 | */ | 1414 | */ |
1386 | if (pid) | 1415 | if (pid) |
1387 | pid = TC_H_MAKE(qid, pid); | 1416 | pid = TC_H_MAKE(qid, pid); |
@@ -1391,7 +1420,8 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
1391 | } | 1420 | } |
1392 | 1421 | ||
1393 | /* OK. Locate qdisc */ | 1422 | /* OK. Locate qdisc */ |
1394 | if ((q = qdisc_lookup(dev, qid)) == NULL) | 1423 | q = qdisc_lookup(dev, qid); |
1424 | if (!q) | ||
1395 | return -ENOENT; | 1425 | return -ENOENT; |
1396 | 1426 | ||
1397 | /* An check that it supports classes */ | 1427 | /* An check that it supports classes */ |
@@ -1411,13 +1441,14 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
1411 | 1441 | ||
1412 | if (cl == 0) { | 1442 | if (cl == 0) { |
1413 | err = -ENOENT; | 1443 | err = -ENOENT; |
1414 | if (n->nlmsg_type != RTM_NEWTCLASS || !(n->nlmsg_flags&NLM_F_CREATE)) | 1444 | if (n->nlmsg_type != RTM_NEWTCLASS || |
1445 | !(n->nlmsg_flags & NLM_F_CREATE)) | ||
1415 | goto out; | 1446 | goto out; |
1416 | } else { | 1447 | } else { |
1417 | switch (n->nlmsg_type) { | 1448 | switch (n->nlmsg_type) { |
1418 | case RTM_NEWTCLASS: | 1449 | case RTM_NEWTCLASS: |
1419 | err = -EEXIST; | 1450 | err = -EEXIST; |
1420 | if (n->nlmsg_flags&NLM_F_EXCL) | 1451 | if (n->nlmsg_flags & NLM_F_EXCL) |
1421 | goto out; | 1452 | goto out; |
1422 | break; | 1453 | break; |
1423 | case RTM_DELTCLASS: | 1454 | case RTM_DELTCLASS: |
@@ -1509,14 +1540,14 @@ static int tclass_notify(struct net *net, struct sk_buff *oskb, | |||
1509 | return -EINVAL; | 1540 | return -EINVAL; |
1510 | } | 1541 | } |
1511 | 1542 | ||
1512 | return rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO); | 1543 | return rtnetlink_send(skb, net, pid, RTNLGRP_TC, |
1544 | n->nlmsg_flags & NLM_F_ECHO); | ||
1513 | } | 1545 | } |
1514 | 1546 | ||
1515 | struct qdisc_dump_args | 1547 | struct qdisc_dump_args { |
1516 | { | 1548 | struct qdisc_walker w; |
1517 | struct qdisc_walker w; | 1549 | struct sk_buff *skb; |
1518 | struct sk_buff *skb; | 1550 | struct netlink_callback *cb; |
1519 | struct netlink_callback *cb; | ||
1520 | }; | 1551 | }; |
1521 | 1552 | ||
1522 | static int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg) | 1553 | static int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walker *arg) |
@@ -1578,7 +1609,7 @@ static int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb, | |||
1578 | 1609 | ||
1579 | static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) | 1610 | static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) |
1580 | { | 1611 | { |
1581 | struct tcmsg *tcm = (struct tcmsg*)NLMSG_DATA(cb->nlh); | 1612 | struct tcmsg *tcm = (struct tcmsg *)NLMSG_DATA(cb->nlh); |
1582 | struct net *net = sock_net(skb->sk); | 1613 | struct net *net = sock_net(skb->sk); |
1583 | struct netdev_queue *dev_queue; | 1614 | struct netdev_queue *dev_queue; |
1584 | struct net_device *dev; | 1615 | struct net_device *dev; |
@@ -1586,7 +1617,8 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) | |||
1586 | 1617 | ||
1587 | if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) | 1618 | if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm))) |
1588 | return 0; | 1619 | return 0; |
1589 | if ((dev = dev_get_by_index(net, tcm->tcm_ifindex)) == NULL) | 1620 | dev = dev_get_by_index(net, tcm->tcm_ifindex); |
1621 | if (!dev) | ||
1590 | return 0; | 1622 | return 0; |
1591 | 1623 | ||
1592 | s_t = cb->args[0]; | 1624 | s_t = cb->args[0]; |
@@ -1595,8 +1627,10 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) | |||
1595 | if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0) | 1627 | if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0) |
1596 | goto done; | 1628 | goto done; |
1597 | 1629 | ||
1598 | dev_queue = &dev->rx_queue; | 1630 | dev_queue = dev_ingress_queue(dev); |
1599 | if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0) | 1631 | if (dev_queue && |
1632 | tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, | ||
1633 | &t, s_t) < 0) | ||
1600 | goto done; | 1634 | goto done; |
1601 | 1635 | ||
1602 | done: | 1636 | done: |
@@ -1607,19 +1641,22 @@ done: | |||
1607 | } | 1641 | } |
1608 | 1642 | ||
1609 | /* Main classifier routine: scans classifier chain attached | 1643 | /* Main classifier routine: scans classifier chain attached |
1610 | to this qdisc, (optionally) tests for protocol and asks | 1644 | * to this qdisc, (optionally) tests for protocol and asks |
1611 | specific classifiers. | 1645 | * specific classifiers. |
1612 | */ | 1646 | */ |
1613 | int tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp, | 1647 | int tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp, |
1614 | struct tcf_result *res) | 1648 | struct tcf_result *res) |
1615 | { | 1649 | { |
1616 | __be16 protocol = skb->protocol; | 1650 | __be16 protocol = skb->protocol; |
1617 | int err = 0; | 1651 | int err; |
1618 | 1652 | ||
1619 | for (; tp; tp = tp->next) { | 1653 | for (; tp; tp = tp->next) { |
1620 | if ((tp->protocol == protocol || | 1654 | if (tp->protocol != protocol && |
1621 | tp->protocol == htons(ETH_P_ALL)) && | 1655 | tp->protocol != htons(ETH_P_ALL)) |
1622 | (err = tp->classify(skb, tp, res)) >= 0) { | 1656 | continue; |
1657 | err = tp->classify(skb, tp, res); | ||
1658 | |||
1659 | if (err >= 0) { | ||
1623 | #ifdef CONFIG_NET_CLS_ACT | 1660 | #ifdef CONFIG_NET_CLS_ACT |
1624 | if (err != TC_ACT_RECLASSIFY && skb->tc_verd) | 1661 | if (err != TC_ACT_RECLASSIFY && skb->tc_verd) |
1625 | skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0); | 1662 | skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0); |
@@ -1635,12 +1672,10 @@ int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, | |||
1635 | struct tcf_result *res) | 1672 | struct tcf_result *res) |
1636 | { | 1673 | { |
1637 | int err = 0; | 1674 | int err = 0; |
1638 | __be16 protocol; | ||
1639 | #ifdef CONFIG_NET_CLS_ACT | 1675 | #ifdef CONFIG_NET_CLS_ACT |
1640 | struct tcf_proto *otp = tp; | 1676 | struct tcf_proto *otp = tp; |
1641 | reclassify: | 1677 | reclassify: |
1642 | #endif | 1678 | #endif |
1643 | protocol = skb->protocol; | ||
1644 | 1679 | ||
1645 | err = tc_classify_compat(skb, tp, res); | 1680 | err = tc_classify_compat(skb, tp, res); |
1646 | #ifdef CONFIG_NET_CLS_ACT | 1681 | #ifdef CONFIG_NET_CLS_ACT |
@@ -1650,11 +1685,11 @@ reclassify: | |||
1650 | 1685 | ||
1651 | if (verd++ >= MAX_REC_LOOP) { | 1686 | if (verd++ >= MAX_REC_LOOP) { |
1652 | if (net_ratelimit()) | 1687 | if (net_ratelimit()) |
1653 | printk(KERN_NOTICE | 1688 | pr_notice("%s: packet reclassify loop" |
1654 | "%s: packet reclassify loop" | ||
1655 | " rule prio %u protocol %02x\n", | 1689 | " rule prio %u protocol %02x\n", |
1656 | tp->q->ops->id, | 1690 | tp->q->ops->id, |
1657 | tp->prio & 0xffff, ntohs(tp->protocol)); | 1691 | tp->prio & 0xffff, |
1692 | ntohs(tp->protocol)); | ||
1658 | return TC_ACT_SHOT; | 1693 | return TC_ACT_SHOT; |
1659 | } | 1694 | } |
1660 | skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd); | 1695 | skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd); |
@@ -1747,7 +1782,7 @@ static int __init pktsched_init(void) | |||
1747 | 1782 | ||
1748 | err = register_pernet_subsys(&psched_net_ops); | 1783 | err = register_pernet_subsys(&psched_net_ops); |
1749 | if (err) { | 1784 | if (err) { |
1750 | printk(KERN_ERR "pktsched_init: " | 1785 | pr_err("pktsched_init: " |
1751 | "cannot initialize per netns operations\n"); | 1786 | "cannot initialize per netns operations\n"); |
1752 | return err; | 1787 | return err; |
1753 | } | 1788 | } |