Kernel generates mapping change message, XFRM_MSG_MAPPING, when a source port chage is detected on a input state with UDP encapsulation set. Kernel generates a message for each IPsec packet with new source port. For a high speed flow per packet mapping change message can be excessive, and can overload the user space listener. Introduce rate limiting for XFRM_MSG_MAPPING message to the user space. The rate limiting is configurable via netlink, when adding a new SA or updating it. Use the new attribute XFRMA_MTIMER_THRESH in seconds. v1->v2 change: update xfrm_sa_len() v2->v3 changes: use u32 insted unsigned long to reduce size of struct xfrm_state fix xfrm_ompat size Reported-by: kernel test robot <lkp@intel.com> accept XFRM_MSG_MAPPING only when XFRMA_ENCAP is present
Unified · Split
| @@ -200,6 +200,11 @@ struct xfrm_state { · 199 unmodified lines | ||
| 200 | 200 | struct xfrm_algo_aead *aead; |
| 201 | 201 | const char *geniv; |
| 202 | 202 | |
| 203 | + /* mapping change rate limiting */ | |
| 204 | + __be16 new_mapping_sport; | |
| 205 | + u32 new_mapping; /* seconds */ | |
| 206 | + u32 mapping_maxage; /* seconds for input SA */ | |
| 207 | + | |
| 203 | 208 | /* Data for encapsulator */ |
| 204 | 209 | struct xfrm_encap_tmpl *encap; |
| 205 | 210 | struct sock __rcu *encap_sk; |
| @@ -313,6 +313,7 @@ enum xfrm_attr_type_t { · 312 unmodified lines | ||
| 313 | 313 | XFRMA_SET_MARK, /* __u32 */ |
| 314 | 314 | XFRMA_SET_MARK_MASK, /* __u32 */ |
| 315 | 315 | XFRMA_IF_ID, /* __u32 */ |
| 316 | + XFRMA_MTIMER_THRESH, /* __u32 in seconds for input SA */ | |
| 316 | 317 | __XFRMA_MAX |
| 317 | 318 | |
| 318 | 319 | #define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */ |
| @@ -127,6 +127,7 @@ static const struct nla_policy compat_policy[XFRMA_MAX+1] = { · 126 unmodified lines | ||
| 127 | 127 | [XFRMA_SET_MARK] = { .type = NLA_U32 }, |
| 128 | 128 | [XFRMA_SET_MARK_MASK] = { .type = NLA_U32 }, |
| 129 | 129 | [XFRMA_IF_ID] = { .type = NLA_U32 }, |
| 130 | + [XFRMA_MTIMER_THRESH] = { .type = NLA_U32 }, | |
| 130 | 131 | }; |
| 131 | 132 | |
| 132 | 133 | static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb, |
| @@ -274,9 +275,10 @@ static int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src) · 141 unmodified lines | ||
| 274 | 275 | case XFRMA_SET_MARK: |
| 275 | 276 | case XFRMA_SET_MARK_MASK: |
| 276 | 277 | case XFRMA_IF_ID: |
| 278 | + case XFRMA_MTIMER_THRESH: | |
| 277 | 279 | return xfrm_nla_cpy(dst, src, nla_len(src)); |
| 278 | 280 | default: |
| 279 | − BUILD_BUG_ON(XFRMA_MAX != XFRMA_IF_ID); | |
| 281 | + BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH); | |
| 280 | 282 | pr_warn_once("unsupported nla_type %d\n", src->nla_type); |
| 281 | 283 | return -EOPNOTSUPP; |
| 282 | 284 | } |
| @@ -431,7 +433,7 @@ static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla, · 148 unmodified lines | ||
| 431 | 433 | int err; |
| 432 | 434 | |
| 433 | 435 | if (type > XFRMA_MAX) { |
| 434 | − BUILD_BUG_ON(XFRMA_MAX != XFRMA_IF_ID); | |
| 436 | + BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH); | |
| 435 | 437 | NL_SET_ERR_MSG(extack, "Bad attribute"); |
| 436 | 438 | return -EOPNOTSUPP; |
| 437 | 439 | } |
| @@ -1593,6 +1593,9 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, · 1592 unmodified lines | ||
| 1593 | 1593 | x->km.seq = orig->km.seq; |
| 1594 | 1594 | x->replay = orig->replay; |
| 1595 | 1595 | x->preplay = orig->preplay; |
| 1596 | + x->mapping_maxage = orig->mapping_maxage; | |
| 1597 | + x->new_mapping = 0; | |
| 1598 | + x->new_mapping_sport = 0; | |
| 1596 | 1599 | |
| 1597 | 1600 | return x; |
| 1598 | 1601 | |
| @@ -2242,7 +2245,7 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) · 643 unmodified lines | ||
| 2242 | 2245 | } |
| 2243 | 2246 | EXPORT_SYMBOL(km_query); |
| 2244 | 2247 | |
| 2245 | −int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) | |
| 2248 | +static int __km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) | |
| 2246 | 2249 | { |
| 2247 | 2250 | int err = -EINVAL; |
| 2248 | 2251 | struct xfrm_mgr *km; |
| @@ -2257,6 +2260,24 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) · 8 unmodified lines | ||
| 2257 | 2260 | rcu_read_unlock(); |
| 2258 | 2261 | return err; |
| 2259 | 2262 | } |
| 2263 | + | |
| 2264 | +int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) | |
| 2265 | +{ | |
| 2266 | + int ret = 0; | |
| 2267 | + | |
| 2268 | + if (x->mapping_maxage) { | |
| 2269 | + if ((jiffies / HZ - x->new_mapping) > x->mapping_maxage || | |
| 2270 | + x->new_mapping_sport != sport) { | |
| 2271 | + x->new_mapping_sport = sport; | |
| 2272 | + x->new_mapping = jiffies / HZ; | |
| 2273 | + ret = __km_new_mapping(x, ipaddr, sport); | |
| 2274 | + } | |
| 2275 | + } else { | |
| 2276 | + ret = __km_new_mapping(x, ipaddr, sport); | |
| 2277 | + } | |
| 2278 | + | |
| 2279 | + return ret; | |
| 2280 | +} | |
| 2260 | 2281 | EXPORT_SYMBOL(km_new_mapping); |
| 2261 | 2282 | |
| 2262 | 2283 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) |
| @@ -282,6 +282,10 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, · 281 unmodified lines | ||
| 282 | 282 | |
| 283 | 283 | err = 0; |
| 284 | 284 | |
| 285 | + if (attrs[XFRMA_MTIMER_THRESH]) | |
| 286 | + if (!attrs[XFRMA_ENCAP]) | |
| 287 | + err = -EINVAL; | |
| 288 | + | |
| 285 | 289 | out: |
| 286 | 290 | return err; |
| 287 | 291 | } |
| @@ -521,6 +525,7 @@ static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs, · 233 unmodified lines | ||
| 521 | 525 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; |
| 522 | 526 | struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; |
| 523 | 527 | struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; |
| 528 | + struct nlattr *mt = attrs[XFRMA_MTIMER_THRESH]; | |
| 524 | 529 | |
| 525 | 530 | if (re) { |
| 526 | 531 | struct xfrm_replay_state_esn *replay_esn; |
| @@ -552,6 +557,9 @@ static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs, · 25 unmodified lines | ||
| 552 | 557 | |
| 553 | 558 | if (rt) |
| 554 | 559 | x->replay_maxdiff = nla_get_u32(rt); |
| 560 | + | |
| 561 | + if (mt) | |
| 562 | + x->mapping_maxage = nla_get_u32(mt); | |
| 555 | 563 | } |
| 556 | 564 | |
| 557 | 565 | static void xfrm_smark_init(struct nlattr **attrs, struct xfrm_mark *m) |
| @@ -1024,8 +1032,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x, · 466 unmodified lines | ||
| 1024 | 1032 | if (ret) |
| 1025 | 1033 | goto out; |
| 1026 | 1034 | } |
| 1027 | − if (x->security) | |
| 1035 | + if (x->security) { | |
| 1028 | 1036 | ret = copy_sec_ctx(x->security, skb); |
| 1037 | + if (ret) | |
| 1038 | + goto out; | |
| 1039 | + } | |
| 1040 | + if (x->mapping_maxage) | |
| 1041 | + ret = nla_put_u32(skb, XFRMA_MTIMER_THRESH, x->mapping_maxage); | |
| 1029 | 1042 | out: |
| 1030 | 1043 | return ret; |
| 1031 | 1044 | } |
| @@ -3069,6 +3082,9 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x) · 2037 unmodified lines | ||
| 3069 | 3082 | /* Must count x->lastused as it may become non-zero behind our back. */ |
| 3070 | 3083 | l += nla_total_size_64bit(sizeof(u64)); |
| 3071 | 3084 | |
| 3085 | + if (x->mapping_maxage) | |
| 3086 | + l += nla_total_size(sizeof(x->mapping_maxage)); | |
| 3087 | + | |
| 3072 | 3088 | return l; |
| 3073 | 3089 | } |
| 3074 | 3090 | |