Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following patchset contains Netfilter updates for net-next:

1) Add nft_reg_store64() and nft_reg_load64() helpers, from Ander Juaristi.

2) Time matching support, also from Ander Juaristi.

3) VLAN support for nfnetlink_log, from Michael Braun.

4) Support for set element deletions from the packet path, also from Ander.

5) Remove __read_mostly from conntrack spinlock, from Li RongQing.

6) Support for updating stateful objects, this also includes the initial
client for this infrastructure: the quota extension. A follow up fix
for the control plane also comes in this batch. Patches from
Fernando Fernandez Mancera.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+287 -31
+38 -10
include/net/netfilter/nf_tables.h
··· 2 2 #ifndef _NET_NF_TABLES_H 3 3 #define _NET_NF_TABLES_H 4 4 5 + #include <asm/unaligned.h> 5 6 #include <linux/list.h> 6 7 #include <linux/netfilter.h> 7 8 #include <linux/netfilter/nfnetlink.h> ··· 103 102 }; 104 103 }; 105 104 106 - /* Store/load an u16 or u8 integer to/from the u32 data register. 105 + /* Store/load an u8, u16 or u64 integer to/from the u32 data register. 107 106 * 108 107 * Note, when using concatenations, register allocation happens at 32-bit 109 108 * level. So for store instruction, pad the rest part with zero to avoid 110 109 * garbage values. 111 110 */ 112 - 113 - static inline void nft_reg_store16(u32 *dreg, u16 val) 114 - { 115 - *dreg = 0; 116 - *(u16 *)dreg = val; 117 - } 118 111 119 112 static inline void nft_reg_store8(u32 *dreg, u8 val) 120 113 { ··· 116 121 *(u8 *)dreg = val; 117 122 } 118 123 124 + static inline u8 nft_reg_load8(u32 *sreg) 125 + { 126 + return *(u8 *)sreg; 127 + } 128 + 129 + static inline void nft_reg_store16(u32 *dreg, u16 val) 130 + { 131 + *dreg = 0; 132 + *(u16 *)dreg = val; 133 + } 134 + 119 135 static inline u16 nft_reg_load16(u32 *sreg) 120 136 { 121 137 return *(u16 *)sreg; 122 138 } 123 139 124 - static inline u8 nft_reg_load8(u32 *sreg) 140 + static inline void nft_reg_store64(u32 *dreg, u64 val) 125 141 { 126 - return *(u8 *)sreg; 142 + put_unaligned(val, (u64 *)dreg); 143 + } 144 + 145 + static inline u64 nft_reg_load64(u32 *sreg) 146 + { 147 + return get_unaligned((u64 *)sreg); 127 148 } 128 149 129 150 static inline void nft_data_copy(u32 *dst, const struct nft_data *src, ··· 302 291 * struct nft_set_ops - nf_tables set operations 303 292 * 304 293 * @lookup: look up an element within the set 294 + * @update: update an element if exists, add it if doesn't exist 295 + * @delete: delete an element 305 296 * @insert: insert new element into set 306 297 * @activate: activate new element in the next generation 307 298 * @deactivate: lookup for element and deactivate it in the next generation 308 299 * @flush: deactivate element in the next generation 309 300 * @remove: remove element from set 310 - * @walk: iterate over all set elemeennts 301 + * @walk: iterate over all set elements 311 302 * @get: get set elements 312 303 * @privsize: function to return size of set private data 313 304 * @init: initialize private data of new set instance 314 305 * @destroy: destroy private data of set instance 315 306 * @elemsize: element private size 307 + * 308 + * Operations lookup, update and delete have simpler interfaces, are faster 309 + * and currently only used in the packet path. All the rest are slower, 310 + * control plane functions. 316 311 */ 317 312 struct nft_set_ops { 318 313 bool (*lookup)(const struct net *net, ··· 333 316 const struct nft_expr *expr, 334 317 struct nft_regs *regs, 335 318 const struct nft_set_ext **ext); 319 + bool (*delete)(const struct nft_set *set, 320 + const u32 *key); 336 321 337 322 int (*insert)(const struct net *net, 338 323 const struct nft_set *set, ··· 1127 1108 * @init: initialize object from netlink attributes 1128 1109 * @destroy: release existing stateful object 1129 1110 * @dump: netlink dump stateful object 1111 + * @update: update stateful object 1130 1112 */ 1131 1113 struct nft_object_ops { 1132 1114 void (*eval)(struct nft_object *obj, ··· 1142 1122 int (*dump)(struct sk_buff *skb, 1143 1123 struct nft_object *obj, 1144 1124 bool reset); 1125 + void (*update)(struct nft_object *obj, 1126 + struct nft_object *newobj); 1145 1127 const struct nft_object_type *type; 1146 1128 }; 1147 1129 ··· 1432 1410 1433 1411 struct nft_trans_obj { 1434 1412 struct nft_object *obj; 1413 + struct nft_object *newobj; 1414 + bool update; 1435 1415 }; 1436 1416 1437 1417 #define nft_trans_obj(trans) \ 1438 1418 (((struct nft_trans_obj *)trans->data)->obj) 1419 + #define nft_trans_obj_newobj(trans) \ 1420 + (((struct nft_trans_obj *)trans->data)->newobj) 1421 + #define nft_trans_obj_update(trans) \ 1422 + (((struct nft_trans_obj *)trans->data)->update) 1439 1423 1440 1424 struct nft_trans_flowtable { 1441 1425 struct nft_flowtable *flowtable;
+7
include/uapi/linux/netfilter/nf_tables.h
··· 636 636 enum nft_dynset_ops { 637 637 NFT_DYNSET_OP_ADD, 638 638 NFT_DYNSET_OP_UPDATE, 639 + NFT_DYNSET_OP_DELETE, 639 640 }; 640 641 641 642 enum nft_dynset_flags { ··· 800 799 * @NFT_META_OIFKIND: packet output interface kind name (dev->rtnl_link_ops->kind) 801 800 * @NFT_META_BRI_IIFPVID: packet input bridge port pvid 802 801 * @NFT_META_BRI_IIFVPROTO: packet input bridge vlan proto 802 + * @NFT_META_TIME_NS: time since epoch (in nanoseconds) 803 + * @NFT_META_TIME_DAY: day of week (from 0 = Sunday to 6 = Saturday) 804 + * @NFT_META_TIME_HOUR: hour of day (in seconds) 803 805 */ 804 806 enum nft_meta_keys { 805 807 NFT_META_LEN, ··· 835 831 NFT_META_OIFKIND, 836 832 NFT_META_BRI_IIFPVID, 837 833 NFT_META_BRI_IIFVPROTO, 834 + NFT_META_TIME_NS, 835 + NFT_META_TIME_DAY, 836 + NFT_META_TIME_HOUR, 838 837 }; 839 838 840 839 /**
+1 -2
net/netfilter/nf_conntrack_core.c
··· 73 73 }; 74 74 75 75 static __read_mostly struct kmem_cache *nf_conntrack_cachep; 76 - static __read_mostly spinlock_t nf_conntrack_locks_all_lock; 77 - static __read_mostly DEFINE_SPINLOCK(nf_conntrack_locks_all_lock); 76 + static DEFINE_SPINLOCK(nf_conntrack_locks_all_lock); 78 77 static __read_mostly bool nf_conntrack_locks_all; 79 78 80 79 /* every gc cycle scans at most 1/GC_MAX_BUCKETS_DIV part of table */
+1 -1
net/netfilter/nf_conntrack_labels.c
··· 11 11 #include <net/netfilter/nf_conntrack_ecache.h> 12 12 #include <net/netfilter/nf_conntrack_labels.h> 13 13 14 - static __read_mostly DEFINE_SPINLOCK(nf_connlabels_lock); 14 + static DEFINE_SPINLOCK(nf_connlabels_lock); 15 15 16 16 static int replace_u32(u32 *address, u32 mask, u32 new) 17 17 {
+74 -7
net/netfilter/nf_tables_api.c
··· 5131 5131 return ERR_PTR(-ENOENT); 5132 5132 } 5133 5133 5134 + static int nf_tables_updobj(const struct nft_ctx *ctx, 5135 + const struct nft_object_type *type, 5136 + const struct nlattr *attr, 5137 + struct nft_object *obj) 5138 + { 5139 + struct nft_object *newobj; 5140 + struct nft_trans *trans; 5141 + int err; 5142 + 5143 + if (!obj->ops->update) 5144 + return -EOPNOTSUPP; 5145 + 5146 + trans = nft_trans_alloc(ctx, NFT_MSG_NEWOBJ, 5147 + sizeof(struct nft_trans_obj)); 5148 + if (!trans) 5149 + return -ENOMEM; 5150 + 5151 + newobj = nft_obj_init(ctx, type, attr); 5152 + if (IS_ERR(newobj)) { 5153 + err = PTR_ERR(newobj); 5154 + goto err1; 5155 + } 5156 + 5157 + nft_trans_obj(trans) = obj; 5158 + nft_trans_obj_update(trans) = true; 5159 + nft_trans_obj_newobj(trans) = newobj; 5160 + list_add_tail(&trans->list, &ctx->net->nft.commit_list); 5161 + 5162 + return 0; 5163 + err1: 5164 + kfree(trans); 5165 + kfree(newobj); 5166 + return err; 5167 + } 5168 + 5134 5169 static int nf_tables_newobj(struct net *net, struct sock *nlsk, 5135 5170 struct sk_buff *skb, const struct nlmsghdr *nlh, 5136 5171 const struct nlattr * const nla[], ··· 5205 5170 NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_NAME]); 5206 5171 return -EEXIST; 5207 5172 } 5208 - return 0; 5173 + if (nlh->nlmsg_flags & NLM_F_REPLACE) 5174 + return -EOPNOTSUPP; 5175 + 5176 + type = nft_obj_type_get(net, objtype); 5177 + nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla); 5178 + 5179 + return nf_tables_updobj(&ctx, type, nla[NFTA_OBJ_DATA], obj); 5209 5180 } 5210 5181 5211 5182 nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla); ··· 6472 6431 } 6473 6432 } 6474 6433 6434 + static void nft_obj_commit_update(struct nft_trans *trans) 6435 + { 6436 + struct nft_object *newobj; 6437 + struct nft_object *obj; 6438 + 6439 + obj = nft_trans_obj(trans); 6440 + newobj = nft_trans_obj_newobj(trans); 6441 + 6442 + obj->ops->update(obj, newobj); 6443 + 6444 + kfree(newobj); 6445 + } 6446 + 6475 6447 static void nft_commit_release(struct nft_trans *trans) 6476 6448 { 6477 6449 switch (trans->msg_type) { ··· 6849 6795 te->set->ndeact--; 6850 6796 break; 6851 6797 case NFT_MSG_NEWOBJ: 6852 - nft_clear(net, nft_trans_obj(trans)); 6853 - nf_tables_obj_notify(&trans->ctx, nft_trans_obj(trans), 6854 - NFT_MSG_NEWOBJ); 6855 - nft_trans_destroy(trans); 6798 + if (nft_trans_obj_update(trans)) { 6799 + nft_obj_commit_update(trans); 6800 + nf_tables_obj_notify(&trans->ctx, 6801 + nft_trans_obj(trans), 6802 + NFT_MSG_NEWOBJ); 6803 + } else { 6804 + nft_clear(net, nft_trans_obj(trans)); 6805 + nf_tables_obj_notify(&trans->ctx, 6806 + nft_trans_obj(trans), 6807 + NFT_MSG_NEWOBJ); 6808 + nft_trans_destroy(trans); 6809 + } 6856 6810 break; 6857 6811 case NFT_MSG_DELOBJ: 6858 6812 nft_obj_del(nft_trans_obj(trans)); ··· 7007 6945 nft_trans_destroy(trans); 7008 6946 break; 7009 6947 case NFT_MSG_NEWOBJ: 7010 - trans->ctx.table->use--; 7011 - nft_obj_del(nft_trans_obj(trans)); 6948 + if (nft_trans_obj_update(trans)) { 6949 + kfree(nft_trans_obj_newobj(trans)); 6950 + nft_trans_destroy(trans); 6951 + } else { 6952 + trans->ctx.table->use--; 6953 + nft_obj_del(nft_trans_obj(trans)); 6954 + } 7012 6955 break; 7013 6956 case NFT_MSG_DELOBJ: 7014 6957 trans->ctx.table->use++;
+5 -4
net/netfilter/nft_byteorder.c
··· 43 43 switch (priv->op) { 44 44 case NFT_BYTEORDER_NTOH: 45 45 for (i = 0; i < priv->len / 8; i++) { 46 - src64 = get_unaligned((u64 *)&src[i]); 47 - put_unaligned_be64(src64, &dst[i]); 46 + src64 = nft_reg_load64(&src[i]); 47 + nft_reg_store64(&dst[i], be64_to_cpu(src64)); 48 48 } 49 49 break; 50 50 case NFT_BYTEORDER_HTON: 51 51 for (i = 0; i < priv->len / 8; i++) { 52 - src64 = get_unaligned_be64(&src[i]); 53 - put_unaligned(src64, (u64 *)&dst[i]); 52 + src64 = (__force __u64) 53 + cpu_to_be64(nft_reg_load64(&src[i])); 54 + nft_reg_store64(&dst[i], src64); 54 55 } 55 56 break; 56 57 }
+6
net/netfilter/nft_dynset.c
··· 84 84 const struct nft_expr *sexpr; 85 85 u64 timeout; 86 86 87 + if (priv->op == NFT_DYNSET_OP_DELETE) { 88 + set->ops->delete(set, &regs->data[priv->sreg_key]); 89 + return; 90 + } 91 + 87 92 if (set->ops->update(set, &regs->data[priv->sreg_key], nft_dynset_new, 88 93 expr, regs, &ext)) { 89 94 sexpr = NULL; ··· 166 161 priv->op = ntohl(nla_get_be32(tb[NFTA_DYNSET_OP])); 167 162 switch (priv->op) { 168 163 case NFT_DYNSET_OP_ADD: 164 + case NFT_DYNSET_OP_DELETE: 169 165 break; 170 166 case NFT_DYNSET_OP_UPDATE: 171 167 if (!(set->flags & NFT_SET_TIMEOUT))
+46
net/netfilter/nft_meta.c
··· 26 26 27 27 #include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */ 28 28 29 + #define NFT_META_SECS_PER_MINUTE 60 30 + #define NFT_META_SECS_PER_HOUR 3600 31 + #define NFT_META_SECS_PER_DAY 86400 32 + #define NFT_META_DAYS_PER_WEEK 7 33 + 29 34 static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state); 35 + 36 + static u8 nft_meta_weekday(unsigned long secs) 37 + { 38 + unsigned int dse; 39 + u8 wday; 40 + 41 + secs -= NFT_META_SECS_PER_MINUTE * sys_tz.tz_minuteswest; 42 + dse = secs / NFT_META_SECS_PER_DAY; 43 + wday = (4 + dse) % NFT_META_DAYS_PER_WEEK; 44 + 45 + return wday; 46 + } 47 + 48 + static u32 nft_meta_hour(unsigned long secs) 49 + { 50 + struct tm tm; 51 + 52 + time64_to_tm(secs, 0, &tm); 53 + 54 + return tm.tm_hour * NFT_META_SECS_PER_HOUR 55 + + tm.tm_min * NFT_META_SECS_PER_MINUTE 56 + + tm.tm_sec; 57 + } 30 58 31 59 void nft_meta_get_eval(const struct nft_expr *expr, 32 60 struct nft_regs *regs, ··· 246 218 goto err; 247 219 strncpy((char *)dest, out->rtnl_link_ops->kind, IFNAMSIZ); 248 220 break; 221 + case NFT_META_TIME_NS: 222 + nft_reg_store64(dest, ktime_get_real_ns()); 223 + break; 224 + case NFT_META_TIME_DAY: 225 + nft_reg_store8(dest, nft_meta_weekday(get_seconds())); 226 + break; 227 + case NFT_META_TIME_HOUR: 228 + *dest = nft_meta_hour(get_seconds()); 229 + break; 249 230 default: 250 231 WARN_ON(1); 251 232 goto err; ··· 367 330 len = sizeof(u8); 368 331 break; 369 332 #endif 333 + case NFT_META_TIME_NS: 334 + len = sizeof(u64); 335 + break; 336 + case NFT_META_TIME_DAY: 337 + len = sizeof(u8); 338 + break; 339 + case NFT_META_TIME_HOUR: 340 + len = sizeof(u32); 341 + break; 370 342 default: 371 343 return -EOPNOTSUPP; 372 344 }
+22 -7
net/netfilter/nft_quota.c
··· 13 13 #include <net/netfilter/nf_tables.h> 14 14 15 15 struct nft_quota { 16 - u64 quota; 16 + atomic64_t quota; 17 17 unsigned long flags; 18 18 atomic64_t consumed; 19 19 }; ··· 21 21 static inline bool nft_overquota(struct nft_quota *priv, 22 22 const struct sk_buff *skb) 23 23 { 24 - return atomic64_add_return(skb->len, &priv->consumed) >= priv->quota; 24 + return atomic64_add_return(skb->len, &priv->consumed) >= 25 + atomic64_read(&priv->quota); 25 26 } 26 27 27 28 static inline bool nft_quota_invert(struct nft_quota *priv) ··· 90 89 return -EOPNOTSUPP; 91 90 } 92 91 93 - priv->quota = quota; 92 + atomic64_set(&priv->quota, quota); 94 93 priv->flags = flags; 95 94 atomic64_set(&priv->consumed, consumed); 96 95 ··· 106 105 return nft_quota_do_init(tb, priv); 107 106 } 108 107 108 + static void nft_quota_obj_update(struct nft_object *obj, 109 + struct nft_object *newobj) 110 + { 111 + struct nft_quota *newpriv = nft_obj_data(newobj); 112 + struct nft_quota *priv = nft_obj_data(obj); 113 + u64 newquota; 114 + 115 + newquota = atomic64_read(&newpriv->quota); 116 + atomic64_set(&priv->quota, newquota); 117 + priv->flags = newpriv->flags; 118 + } 119 + 109 120 static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv, 110 121 bool reset) 111 122 { 112 - u64 consumed, consumed_cap; 123 + u64 consumed, consumed_cap, quota; 113 124 u32 flags = priv->flags; 114 125 115 126 /* Since we inconditionally increment consumed quota for each packet ··· 129 116 * userspace. 130 117 */ 131 118 consumed = atomic64_read(&priv->consumed); 132 - if (consumed >= priv->quota) { 133 - consumed_cap = priv->quota; 119 + quota = atomic64_read(&priv->quota); 120 + if (consumed >= quota) { 121 + consumed_cap = quota; 134 122 flags |= NFT_QUOTA_F_DEPLETED; 135 123 } else { 136 124 consumed_cap = consumed; 137 125 } 138 126 139 - if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(priv->quota), 127 + if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(quota), 140 128 NFTA_QUOTA_PAD) || 141 129 nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed_cap), 142 130 NFTA_QUOTA_PAD) || ··· 169 155 .init = nft_quota_obj_init, 170 156 .eval = nft_quota_obj_eval, 171 157 .dump = nft_quota_obj_dump, 158 + .update = nft_quota_obj_update, 172 159 }; 173 160 174 161 static struct nft_object_type nft_quota_obj_type __read_mostly = {
+19
net/netfilter/nft_set_hash.c
··· 234 234 rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params); 235 235 } 236 236 237 + static bool nft_rhash_delete(const struct nft_set *set, 238 + const u32 *key) 239 + { 240 + struct nft_rhash *priv = nft_set_priv(set); 241 + struct nft_rhash_cmp_arg arg = { 242 + .genmask = NFT_GENMASK_ANY, 243 + .set = set, 244 + .key = key, 245 + }; 246 + struct nft_rhash_elem *he; 247 + 248 + he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params); 249 + if (he == NULL) 250 + return false; 251 + 252 + return rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params) == 0; 253 + } 254 + 237 255 static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set, 238 256 struct nft_set_iter *iter) 239 257 { ··· 680 662 .remove = nft_rhash_remove, 681 663 .lookup = nft_rhash_lookup, 682 664 .update = nft_rhash_update, 665 + .delete = nft_rhash_delete, 683 666 .walk = nft_rhash_walk, 684 667 .get = nft_rhash_get, 685 668 },