0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/init.h>
0008 #include <linux/module.h>
0009 #include <linux/list.h>
0010 #include <linux/netlink.h>
0011 #include <linux/netfilter.h>
0012 #include <linux/netfilter/nf_tables.h>
0013 #include <net/netfilter/nf_tables_core.h>
0014
0015 struct nft_bitmap_elem {
0016 struct list_head head;
0017 struct nft_set_ext ext;
0018 };
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 struct nft_bitmap {
0046 struct list_head list;
0047 u16 bitmap_size;
0048 u8 bitmap[];
0049 };
0050
0051 static inline void nft_bitmap_location(const struct nft_set *set,
0052 const void *key,
0053 u32 *idx, u32 *off)
0054 {
0055 u32 k;
0056
0057 if (set->klen == 2)
0058 k = *(u16 *)key;
0059 else
0060 k = *(u8 *)key;
0061 k <<= 1;
0062
0063 *idx = k / BITS_PER_BYTE;
0064 *off = k % BITS_PER_BYTE;
0065 }
0066
0067
0068
0069
0070 static inline bool
0071 nft_bitmap_active(const u8 *bitmap, u32 idx, u32 off, u8 genmask)
0072 {
0073 return (bitmap[idx] & (0x3 << off)) & (genmask << off);
0074 }
0075
0076 INDIRECT_CALLABLE_SCOPE
0077 bool nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
0078 const u32 *key, const struct nft_set_ext **ext)
0079 {
0080 const struct nft_bitmap *priv = nft_set_priv(set);
0081 u8 genmask = nft_genmask_cur(net);
0082 u32 idx, off;
0083
0084 nft_bitmap_location(set, key, &idx, &off);
0085
0086 return nft_bitmap_active(priv->bitmap, idx, off, genmask);
0087 }
0088
0089 static struct nft_bitmap_elem *
0090 nft_bitmap_elem_find(const struct nft_set *set, struct nft_bitmap_elem *this,
0091 u8 genmask)
0092 {
0093 const struct nft_bitmap *priv = nft_set_priv(set);
0094 struct nft_bitmap_elem *be;
0095
0096 list_for_each_entry_rcu(be, &priv->list, head) {
0097 if (memcmp(nft_set_ext_key(&be->ext),
0098 nft_set_ext_key(&this->ext), set->klen) ||
0099 !nft_set_elem_active(&be->ext, genmask))
0100 continue;
0101
0102 return be;
0103 }
0104 return NULL;
0105 }
0106
0107 static void *nft_bitmap_get(const struct net *net, const struct nft_set *set,
0108 const struct nft_set_elem *elem, unsigned int flags)
0109 {
0110 const struct nft_bitmap *priv = nft_set_priv(set);
0111 u8 genmask = nft_genmask_cur(net);
0112 struct nft_bitmap_elem *be;
0113
0114 list_for_each_entry_rcu(be, &priv->list, head) {
0115 if (memcmp(nft_set_ext_key(&be->ext), elem->key.val.data, set->klen) ||
0116 !nft_set_elem_active(&be->ext, genmask))
0117 continue;
0118
0119 return be;
0120 }
0121 return ERR_PTR(-ENOENT);
0122 }
0123
0124 static int nft_bitmap_insert(const struct net *net, const struct nft_set *set,
0125 const struct nft_set_elem *elem,
0126 struct nft_set_ext **ext)
0127 {
0128 struct nft_bitmap *priv = nft_set_priv(set);
0129 struct nft_bitmap_elem *new = elem->priv, *be;
0130 u8 genmask = nft_genmask_next(net);
0131 u32 idx, off;
0132
0133 be = nft_bitmap_elem_find(set, new, genmask);
0134 if (be) {
0135 *ext = &be->ext;
0136 return -EEXIST;
0137 }
0138
0139 nft_bitmap_location(set, nft_set_ext_key(&new->ext), &idx, &off);
0140
0141 priv->bitmap[idx] |= (genmask << off);
0142 list_add_tail_rcu(&new->head, &priv->list);
0143
0144 return 0;
0145 }
0146
0147 static void nft_bitmap_remove(const struct net *net,
0148 const struct nft_set *set,
0149 const struct nft_set_elem *elem)
0150 {
0151 struct nft_bitmap *priv = nft_set_priv(set);
0152 struct nft_bitmap_elem *be = elem->priv;
0153 u8 genmask = nft_genmask_next(net);
0154 u32 idx, off;
0155
0156 nft_bitmap_location(set, nft_set_ext_key(&be->ext), &idx, &off);
0157
0158 priv->bitmap[idx] &= ~(genmask << off);
0159 list_del_rcu(&be->head);
0160 }
0161
0162 static void nft_bitmap_activate(const struct net *net,
0163 const struct nft_set *set,
0164 const struct nft_set_elem *elem)
0165 {
0166 struct nft_bitmap *priv = nft_set_priv(set);
0167 struct nft_bitmap_elem *be = elem->priv;
0168 u8 genmask = nft_genmask_next(net);
0169 u32 idx, off;
0170
0171 nft_bitmap_location(set, nft_set_ext_key(&be->ext), &idx, &off);
0172
0173 priv->bitmap[idx] |= (genmask << off);
0174 nft_set_elem_change_active(net, set, &be->ext);
0175 }
0176
0177 static bool nft_bitmap_flush(const struct net *net,
0178 const struct nft_set *set, void *_be)
0179 {
0180 struct nft_bitmap *priv = nft_set_priv(set);
0181 u8 genmask = nft_genmask_next(net);
0182 struct nft_bitmap_elem *be = _be;
0183 u32 idx, off;
0184
0185 nft_bitmap_location(set, nft_set_ext_key(&be->ext), &idx, &off);
0186
0187 priv->bitmap[idx] &= ~(genmask << off);
0188 nft_set_elem_change_active(net, set, &be->ext);
0189
0190 return true;
0191 }
0192
0193 static void *nft_bitmap_deactivate(const struct net *net,
0194 const struct nft_set *set,
0195 const struct nft_set_elem *elem)
0196 {
0197 struct nft_bitmap *priv = nft_set_priv(set);
0198 struct nft_bitmap_elem *this = elem->priv, *be;
0199 u8 genmask = nft_genmask_next(net);
0200 u32 idx, off;
0201
0202 nft_bitmap_location(set, elem->key.val.data, &idx, &off);
0203
0204 be = nft_bitmap_elem_find(set, this, genmask);
0205 if (!be)
0206 return NULL;
0207
0208
0209 priv->bitmap[idx] &= ~(genmask << off);
0210 nft_set_elem_change_active(net, set, &be->ext);
0211
0212 return be;
0213 }
0214
0215 static void nft_bitmap_walk(const struct nft_ctx *ctx,
0216 struct nft_set *set,
0217 struct nft_set_iter *iter)
0218 {
0219 const struct nft_bitmap *priv = nft_set_priv(set);
0220 struct nft_bitmap_elem *be;
0221 struct nft_set_elem elem;
0222
0223 list_for_each_entry_rcu(be, &priv->list, head) {
0224 if (iter->count < iter->skip)
0225 goto cont;
0226 if (!nft_set_elem_active(&be->ext, iter->genmask))
0227 goto cont;
0228
0229 elem.priv = be;
0230
0231 iter->err = iter->fn(ctx, set, iter, &elem);
0232
0233 if (iter->err < 0)
0234 return;
0235 cont:
0236 iter->count++;
0237 }
0238 }
0239
0240
0241
0242
0243
0244 static inline u32 nft_bitmap_size(u32 klen)
0245 {
0246 return ((2 << ((klen * BITS_PER_BYTE) - 1)) / BITS_PER_BYTE) << 1;
0247 }
0248
0249 static inline u64 nft_bitmap_total_size(u32 klen)
0250 {
0251 return sizeof(struct nft_bitmap) + nft_bitmap_size(klen);
0252 }
0253
0254 static u64 nft_bitmap_privsize(const struct nlattr * const nla[],
0255 const struct nft_set_desc *desc)
0256 {
0257 u32 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
0258
0259 return nft_bitmap_total_size(klen);
0260 }
0261
0262 static int nft_bitmap_init(const struct nft_set *set,
0263 const struct nft_set_desc *desc,
0264 const struct nlattr * const nla[])
0265 {
0266 struct nft_bitmap *priv = nft_set_priv(set);
0267
0268 INIT_LIST_HEAD(&priv->list);
0269 priv->bitmap_size = nft_bitmap_size(set->klen);
0270
0271 return 0;
0272 }
0273
0274 static void nft_bitmap_destroy(const struct nft_set *set)
0275 {
0276 struct nft_bitmap *priv = nft_set_priv(set);
0277 struct nft_bitmap_elem *be, *n;
0278
0279 list_for_each_entry_safe(be, n, &priv->list, head)
0280 nft_set_elem_destroy(set, be, true);
0281 }
0282
0283 static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features,
0284 struct nft_set_estimate *est)
0285 {
0286
0287 if (desc->klen > 2)
0288 return false;
0289 else if (desc->expr)
0290 return false;
0291
0292 est->size = nft_bitmap_total_size(desc->klen);
0293 est->lookup = NFT_SET_CLASS_O_1;
0294 est->space = NFT_SET_CLASS_O_1;
0295
0296 return true;
0297 }
0298
0299 const struct nft_set_type nft_set_bitmap_type = {
0300 .ops = {
0301 .privsize = nft_bitmap_privsize,
0302 .elemsize = offsetof(struct nft_bitmap_elem, ext),
0303 .estimate = nft_bitmap_estimate,
0304 .init = nft_bitmap_init,
0305 .destroy = nft_bitmap_destroy,
0306 .insert = nft_bitmap_insert,
0307 .remove = nft_bitmap_remove,
0308 .deactivate = nft_bitmap_deactivate,
0309 .flush = nft_bitmap_flush,
0310 .activate = nft_bitmap_activate,
0311 .lookup = nft_bitmap_lookup,
0312 .walk = nft_bitmap_walk,
0313 .get = nft_bitmap_get,
0314 },
0315 };