hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/net/sched/cls_u32.c
....@@ -716,11 +716,17 @@
716716 struct nlattr *est, bool ovr,
717717 struct netlink_ext_ack *extack)
718718 {
719
- int err;
719
+ int err, ifindex = -1;
720720
721721 err = tcf_exts_validate(net, tp, tb, est, &n->exts, ovr, true, extack);
722722 if (err < 0)
723723 return err;
724
+
725
+ if (tb[TCA_U32_INDEV]) {
726
+ ifindex = tcf_change_indev(net, tb[TCA_U32_INDEV], extack);
727
+ if (ifindex < 0)
728
+ return -EINVAL;
729
+ }
724730
725731 if (tb[TCA_U32_LINK]) {
726732 u32 handle = nla_get_u32(tb[TCA_U32_LINK]);
....@@ -756,13 +762,9 @@
756762 tcf_bind_filter(tp, &n->res, base);
757763 }
758764
759
- if (tb[TCA_U32_INDEV]) {
760
- int ret;
761
- ret = tcf_change_indev(net, tb[TCA_U32_INDEV], extack);
762
- if (ret < 0)
763
- return -EINVAL;
764
- n->ifindex = ret;
765
- }
765
+ if (ifindex >= 0)
766
+ n->ifindex = ifindex;
767
+
766768 return 0;
767769 }
768770
....@@ -810,7 +812,6 @@
810812
811813 new->ifindex = n->ifindex;
812814 new->fshift = n->fshift;
813
- new->res = n->res;
814815 new->flags = n->flags;
815816 RCU_INIT_POINTER(new->ht_down, ht);
816817
....@@ -997,18 +998,62 @@
997998 return -EINVAL;
998999 }
9991000
1001
+ /* At this point, we need to derive the new handle that will be used to
1002
+ * uniquely map the identity of this table match entry. The
1003
+ * identity of the entry that we need to construct is 32 bits made of:
1004
+ * htid(12b):bucketid(8b):node/entryid(12b)
1005
+ *
1006
+ * At this point _we have the table(ht)_ in which we will insert this
1007
+ * entry. We carry the table's id in variable "htid".
1008
+ * Note that earlier code picked the ht selection either by a) the user
1009
+ * providing the htid specified via TCA_U32_HASH attribute or b) when
1010
+ * no such attribute is passed then the root ht, is default to at ID
1011
+ * 0x[800][00][000]. Rule: the root table has a single bucket with ID 0.
1012
+ * If OTOH the user passed us the htid, they may also pass a bucketid of
1013
+ * choice. 0 is fine. For example a user htid is 0x[600][01][000] it is
1014
+ * indicating hash bucketid of 1. Rule: the entry/node ID _cannot_ be
1015
+ * passed via the htid, so even if it was non-zero it will be ignored.
1016
+ *
1017
+ * We may also have a handle, if the user passed one. The handle also
1018
+ * carries the same addressing of htid(12b):bucketid(8b):node/entryid(12b).
1019
+ * Rule: the bucketid on the handle is ignored even if one was passed;
1020
+ * rather the value on "htid" is always assumed to be the bucketid.
1021
+ */
10001022 if (handle) {
1023
+ /* Rule: The htid from handle and tableid from htid must match */
10011024 if (TC_U32_HTID(handle) && TC_U32_HTID(handle ^ htid)) {
10021025 NL_SET_ERR_MSG_MOD(extack, "Handle specified hash table address mismatch");
10031026 return -EINVAL;
10041027 }
1005
- handle = htid | TC_U32_NODE(handle);
1006
- err = idr_alloc_u32(&ht->handle_idr, NULL, &handle, handle,
1007
- GFP_KERNEL);
1008
- if (err)
1009
- return err;
1010
- } else
1028
+ /* Ok, so far we have a valid htid(12b):bucketid(8b) but we
1029
+ * need to finalize the table entry identification with the last
1030
+ * part - the node/entryid(12b)). Rule: Nodeid _cannot be 0_ for
1031
+ * entries. Rule: nodeid of 0 is reserved only for tables(see
1032
+ * earlier code which processes TC_U32_DIVISOR attribute).
1033
+ * Rule: The nodeid can only be derived from the handle (and not
1034
+ * htid).
1035
+ * Rule: if the handle specified zero for the node id example
1036
+ * 0x60000000, then pick a new nodeid from the pool of IDs
1037
+ * this hash table has been allocating from.
1038
+ * If OTOH it is specified (i.e for example the user passed a
1039
+ * handle such as 0x60000123), then we use it generate our final
1040
+ * handle which is used to uniquely identify the match entry.
1041
+ */
1042
+ if (!TC_U32_NODE(handle)) {
1043
+ handle = gen_new_kid(ht, htid);
1044
+ } else {
1045
+ handle = htid | TC_U32_NODE(handle);
1046
+ err = idr_alloc_u32(&ht->handle_idr, NULL, &handle,
1047
+ handle, GFP_KERNEL);
1048
+ if (err)
1049
+ return err;
1050
+ }
1051
+ } else {
1052
+ /* The user did not give us a handle; lets just generate one
1053
+ * from the table's pool of nodeids.
1054
+ */
10111055 handle = gen_new_kid(ht, htid);
1056
+ }
10121057
10131058 if (tb[TCA_U32_SEL] == NULL) {
10141059 NL_SET_ERR_MSG_MOD(extack, "Selector not specified");