Allow to match on the cgroupsv2 id from ancestor level.
Unified · Split
| @@ -1014,11 +1014,13 @@ enum nft_rt_attributes { · 1013 unmodified lines | ||
| 1014 | 1014 | * |
| 1015 | 1015 | * @NFTA_SOCKET_KEY: socket key to match |
| 1016 | 1016 | * @NFTA_SOCKET_DREG: destination register |
| 1017 | + * @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2) | |
| 1017 | 1018 | */ |
| 1018 | 1019 | enum nft_socket_attributes { |
| 1019 | 1020 | NFTA_SOCKET_UNSPEC, |
| 1020 | 1021 | NFTA_SOCKET_KEY, |
| 1021 | 1022 | NFTA_SOCKET_DREG, |
| 1023 | + NFTA_SOCKET_LEVEL, | |
| 1022 | 1024 | __NFTA_SOCKET_MAX |
| 1023 | 1025 | }; |
| 1024 | 1026 | #define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1) |
| @@ -1029,11 +1031,13 @@ enum nft_socket_attributes { · 4 unmodified lines | ||
| 1029 | 1031 | * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option |
| 1030 | 1032 | * @NFT_SOCKET_MARK: Value of the socket mark |
| 1031 | 1033 | * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0) |
| 1034 | + * @NFT_SOCKET_CGROUPV2: Match on cgroups version 2 | |
| 1032 | 1035 | */ |
| 1033 | 1036 | enum nft_socket_keys { |
| 1034 | 1037 | NFT_SOCKET_TRANSPARENT, |
| 1035 | 1038 | NFT_SOCKET_MARK, |
| 1036 | 1039 | NFT_SOCKET_WILDCARD, |
| 1040 | + NFT_SOCKET_CGROUPV2, | |
| 1037 | 1041 | __NFT_SOCKET_MAX |
| 1038 | 1042 | }; |
| 1039 | 1043 | #define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1) |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | struct nft_socket { |
| 11 | 11 | enum nft_socket_keys key:8; |
| 12 | + u8 level; | |
| 12 | 13 | union { |
| 13 | 14 | u8 dreg; |
| 14 | 15 | }; |
| @@ -33,6 +34,26 @@ static void nft_socket_wildcard(const struct nft_pktinfo *pkt, · 18 unmodified lines | ||
| 33 | 34 | } |
| 34 | 35 | } |
| 35 | 36 | |
| 37 | +#ifdef CONFIG_CGROUPS | |
| 38 | +static noinline bool | |
| 39 | +nft_sock_get_eval_cgroupv2(u32 *dest, const struct nft_pktinfo *pkt, u32 level) | |
| 40 | +{ | |
| 41 | + struct sock *sk = skb_to_full_sk(pkt->skb); | |
| 42 | + struct cgroup *cgrp; | |
| 43 | + | |
| 44 | + if (!sk || !sk_fullsock(sk) || !net_eq(nft_net(pkt), sock_net(sk))) | |
| 45 | + return false; | |
| 46 | + | |
| 47 | + cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data); | |
| 48 | + if (level > cgrp->level) | |
| 49 | + return false; | |
| 50 | + | |
| 51 | + memcpy(dest, &cgrp->ancestor_ids[level], sizeof(u64)); | |
| 52 | + | |
| 53 | + return true; | |
| 54 | +} | |
| 55 | +#endif | |
| 56 | + | |
| 36 | 57 | static void nft_socket_eval(const struct nft_expr *expr, |
| 37 | 58 | struct nft_regs *regs, |
| 38 | 59 | const struct nft_pktinfo *pkt) |
| @@ -85,6 +106,14 @@ static void nft_socket_eval(const struct nft_expr *expr, · 46 unmodified lines | ||
| 85 | 106 | } |
| 86 | 107 | nft_socket_wildcard(pkt, regs, sk, dest); |
| 87 | 108 | break; |
| 109 | +#ifdef CONFIG_CGROUPS | |
| 110 | + case NFT_SOCKET_CGROUPV2: | |
| 111 | + if (!nft_sock_get_eval_cgroupv2(dest, pkt, priv->level)) { | |
| 112 | + regs->verdict.code = NFT_BREAK; | |
| 113 | + return; | |
| 114 | + } | |
| 115 | + break; | |
| 116 | +#endif | |
| 88 | 117 | default: |
| 89 | 118 | WARN_ON(1); |
| 90 | 119 | regs->verdict.code = NFT_BREAK; |
| @@ -97,6 +126,7 @@ static void nft_socket_eval(const struct nft_expr *expr, · 6 unmodified lines | ||
| 97 | 126 | static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = { |
| 98 | 127 | [NFTA_SOCKET_KEY] = { .type = NLA_U32 }, |
| 99 | 128 | [NFTA_SOCKET_DREG] = { .type = NLA_U32 }, |
| 129 | + [NFTA_SOCKET_LEVEL] = { .type = NLA_U32 }, | |
| 100 | 130 | }; |
| 101 | 131 | |
| 102 | 132 | static int nft_socket_init(const struct nft_ctx *ctx, |
| @@ -104,7 +134,7 @@ static int nft_socket_init(const struct nft_ctx *ctx, · 1 unmodified line | ||
| 104 | 134 | const struct nlattr * const tb[]) |
| 105 | 135 | { |
| 106 | 136 | struct nft_socket *priv = nft_expr_priv(expr); |
| 107 | − unsigned int len; | |
| 137 | + unsigned int len, level; | |
| 108 | 138 | |
| 109 | 139 | if (!tb[NFTA_SOCKET_DREG] || !tb[NFTA_SOCKET_KEY]) |
| 110 | 140 | return -EINVAL; |
| @@ -129,6 +159,19 @@ static int nft_socket_init(const struct nft_ctx *ctx, · 18 unmodified lines | ||
| 129 | 159 | case NFT_SOCKET_MARK: |
| 130 | 160 | len = sizeof(u32); |
| 131 | 161 | break; |
| 162 | +#ifdef CONFIG_CGROUPS | |
| 163 | + case NFT_SOCKET_CGROUPV2: | |
| 164 | + if (!tb[NFTA_SOCKET_LEVEL]) | |
| 165 | + return -EINVAL; | |
| 166 | + | |
| 167 | + level = ntohl(nla_get_u32(tb[NFTA_SOCKET_LEVEL])); | |
| 168 | + if (level > 255) | |
| 169 | + return -EOPNOTSUPP; | |
| 170 | + | |
| 171 | + priv->level = level; | |
| 172 | + len = sizeof(u64); | |
| 173 | + break; | |
| 174 | +#endif | |
| 132 | 175 | default: |
| 133 | 176 | return -EOPNOTSUPP; |
| 134 | 177 | } |
| @@ -146,6 +189,9 @@ static int nft_socket_dump(struct sk_buff *skb, · 11 unmodified lines | ||
| 146 | 189 | return -1; |
| 147 | 190 | if (nft_dump_register(skb, NFTA_SOCKET_DREG, priv->dreg)) |
| 148 | 191 | return -1; |
| 192 | + if (priv->key == NFT_SOCKET_CGROUPV2 && | |
| 193 | + nla_put_u32(skb, NFTA_SOCKET_LEVEL, htonl(priv->level))) | |
| 194 | + return -1; | |
| 149 | 195 | return 0; |
| 150 | 196 | } |
| 151 | 197 | |