diff options
author | David S. Miller <davem@davemloft.net> | 2011-05-08 20:12:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-05-09 00:24:06 -0400 |
commit | 77968b78242ee25e2a4d759f0fca8dd52df6d479 (patch) | |
tree | 6de21f3a2efe49cb30ea8109fdfc79d30d6b27a3 /net/ipv4/icmp.c | |
parent | e474995f290ff7bc236b549aa9a89ae445ee5b1b (diff) |
ipv4: Pass flow keys down into datagram packet building engine.
This way ip_output.c no longer needs rt->rt_{src,dst}.
We already have these keys sitting, ready and waiting, on the stack or
in a socket structure.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/icmp.c')
-rw-r--r-- | net/ipv4/icmp.c | 74 |
1 files changed, 36 insertions, 38 deletions
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index cfeca3c2152d..be5cc8d04c00 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
@@ -290,6 +290,7 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd, | |||
290 | } | 290 | } |
291 | 291 | ||
292 | static void icmp_push_reply(struct icmp_bxm *icmp_param, | 292 | static void icmp_push_reply(struct icmp_bxm *icmp_param, |
293 | struct flowi4 *fl4, | ||
293 | struct ipcm_cookie *ipc, struct rtable **rt) | 294 | struct ipcm_cookie *ipc, struct rtable **rt) |
294 | { | 295 | { |
295 | struct sock *sk; | 296 | struct sock *sk; |
@@ -315,7 +316,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, | |||
315 | icmp_param->head_len, csum); | 316 | icmp_param->head_len, csum); |
316 | icmph->checksum = csum_fold(csum); | 317 | icmph->checksum = csum_fold(csum); |
317 | skb->ip_summed = CHECKSUM_NONE; | 318 | skb->ip_summed = CHECKSUM_NONE; |
318 | ip_push_pending_frames(sk); | 319 | ip_push_pending_frames(sk, fl4); |
319 | } | 320 | } |
320 | } | 321 | } |
321 | 322 | ||
@@ -328,6 +329,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) | |||
328 | struct ipcm_cookie ipc; | 329 | struct ipcm_cookie ipc; |
329 | struct rtable *rt = skb_rtable(skb); | 330 | struct rtable *rt = skb_rtable(skb); |
330 | struct net *net = dev_net(rt->dst.dev); | 331 | struct net *net = dev_net(rt->dst.dev); |
332 | struct flowi4 fl4; | ||
331 | struct sock *sk; | 333 | struct sock *sk; |
332 | struct inet_sock *inet; | 334 | struct inet_sock *inet; |
333 | __be32 daddr; | 335 | __be32 daddr; |
@@ -351,57 +353,52 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) | |||
351 | if (ipc.opt->opt.srr) | 353 | if (ipc.opt->opt.srr) |
352 | daddr = icmp_param->replyopts.opt.opt.faddr; | 354 | daddr = icmp_param->replyopts.opt.opt.faddr; |
353 | } | 355 | } |
354 | { | 356 | memset(&fl4, 0, sizeof(fl4)); |
355 | struct flowi4 fl4 = { | 357 | fl4.daddr = daddr; |
356 | .daddr = daddr, | 358 | fl4.saddr = rt->rt_spec_dst; |
357 | .saddr = rt->rt_spec_dst, | 359 | fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); |
358 | .flowi4_tos = RT_TOS(ip_hdr(skb)->tos), | 360 | fl4.flowi4_proto = IPPROTO_ICMP; |
359 | .flowi4_proto = IPPROTO_ICMP, | 361 | security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); |
360 | }; | 362 | rt = ip_route_output_key(net, &fl4); |
361 | security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); | 363 | if (IS_ERR(rt)) |
362 | rt = ip_route_output_key(net, &fl4); | 364 | goto out_unlock; |
363 | if (IS_ERR(rt)) | ||
364 | goto out_unlock; | ||
365 | } | ||
366 | if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type, | 365 | if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type, |
367 | icmp_param->data.icmph.code)) | 366 | icmp_param->data.icmph.code)) |
368 | icmp_push_reply(icmp_param, &ipc, &rt); | 367 | icmp_push_reply(icmp_param, &fl4, &ipc, &rt); |
369 | ip_rt_put(rt); | 368 | ip_rt_put(rt); |
370 | out_unlock: | 369 | out_unlock: |
371 | icmp_xmit_unlock(sk); | 370 | icmp_xmit_unlock(sk); |
372 | } | 371 | } |
373 | 372 | ||
374 | static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, | 373 | static struct rtable *icmp_route_lookup(struct net *net, |
374 | struct flowi4 *fl4, | ||
375 | struct sk_buff *skb_in, | ||
375 | const struct iphdr *iph, | 376 | const struct iphdr *iph, |
376 | __be32 saddr, u8 tos, | 377 | __be32 saddr, u8 tos, |
377 | int type, int code, | 378 | int type, int code, |
378 | struct icmp_bxm *param) | 379 | struct icmp_bxm *param) |
379 | { | 380 | { |
380 | struct flowi4 fl4 = { | ||
381 | .daddr = (param->replyopts.opt.opt.srr ? | ||
382 | param->replyopts.opt.opt.faddr : iph->saddr), | ||
383 | .saddr = saddr, | ||
384 | .flowi4_tos = RT_TOS(tos), | ||
385 | .flowi4_proto = IPPROTO_ICMP, | ||
386 | .fl4_icmp_type = type, | ||
387 | .fl4_icmp_code = code, | ||
388 | }; | ||
389 | struct rtable *rt, *rt2; | 381 | struct rtable *rt, *rt2; |
390 | int err; | 382 | int err; |
391 | 383 | ||
392 | security_skb_classify_flow(skb_in, flowi4_to_flowi(&fl4)); | 384 | memset(fl4, 0, sizeof(*fl4)); |
393 | rt = __ip_route_output_key(net, &fl4); | 385 | fl4->daddr = (param->replyopts.opt.opt.srr ? |
386 | param->replyopts.opt.opt.faddr : iph->saddr); | ||
387 | fl4->saddr = saddr; | ||
388 | fl4->flowi4_tos = RT_TOS(tos); | ||
389 | fl4->flowi4_proto = IPPROTO_ICMP; | ||
390 | fl4->fl4_icmp_type = type; | ||
391 | fl4->fl4_icmp_code = code; | ||
392 | security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4)); | ||
393 | rt = __ip_route_output_key(net, fl4); | ||
394 | if (IS_ERR(rt)) | 394 | if (IS_ERR(rt)) |
395 | return rt; | 395 | return rt; |
396 | 396 | ||
397 | /* No need to clone since we're just using its address. */ | 397 | /* No need to clone since we're just using its address. */ |
398 | rt2 = rt; | 398 | rt2 = rt; |
399 | 399 | ||
400 | if (!fl4.saddr) | ||
401 | fl4.saddr = rt->rt_src; | ||
402 | |||
403 | rt = (struct rtable *) xfrm_lookup(net, &rt->dst, | 400 | rt = (struct rtable *) xfrm_lookup(net, &rt->dst, |
404 | flowi4_to_flowi(&fl4), NULL, 0); | 401 | flowi4_to_flowi(fl4), NULL, 0); |
405 | if (!IS_ERR(rt)) { | 402 | if (!IS_ERR(rt)) { |
406 | if (rt != rt2) | 403 | if (rt != rt2) |
407 | return rt; | 404 | return rt; |
@@ -410,19 +407,19 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, | |||
410 | } else | 407 | } else |
411 | return rt; | 408 | return rt; |
412 | 409 | ||
413 | err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(&fl4), AF_INET); | 410 | err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(fl4), AF_INET); |
414 | if (err) | 411 | if (err) |
415 | goto relookup_failed; | 412 | goto relookup_failed; |
416 | 413 | ||
417 | if (inet_addr_type(net, fl4.saddr) == RTN_LOCAL) { | 414 | if (inet_addr_type(net, fl4->saddr) == RTN_LOCAL) { |
418 | rt2 = __ip_route_output_key(net, &fl4); | 415 | rt2 = __ip_route_output_key(net, fl4); |
419 | if (IS_ERR(rt2)) | 416 | if (IS_ERR(rt2)) |
420 | err = PTR_ERR(rt2); | 417 | err = PTR_ERR(rt2); |
421 | } else { | 418 | } else { |
422 | struct flowi4 fl4_2 = {}; | 419 | struct flowi4 fl4_2 = {}; |
423 | unsigned long orefdst; | 420 | unsigned long orefdst; |
424 | 421 | ||
425 | fl4_2.daddr = fl4.saddr; | 422 | fl4_2.daddr = fl4->saddr; |
426 | rt2 = ip_route_output_key(net, &fl4_2); | 423 | rt2 = ip_route_output_key(net, &fl4_2); |
427 | if (IS_ERR(rt2)) { | 424 | if (IS_ERR(rt2)) { |
428 | err = PTR_ERR(rt2); | 425 | err = PTR_ERR(rt2); |
@@ -430,7 +427,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, | |||
430 | } | 427 | } |
431 | /* Ugh! */ | 428 | /* Ugh! */ |
432 | orefdst = skb_in->_skb_refdst; /* save old refdst */ | 429 | orefdst = skb_in->_skb_refdst; /* save old refdst */ |
433 | err = ip_route_input(skb_in, fl4.daddr, fl4.saddr, | 430 | err = ip_route_input(skb_in, fl4->daddr, fl4->saddr, |
434 | RT_TOS(tos), rt2->dst.dev); | 431 | RT_TOS(tos), rt2->dst.dev); |
435 | 432 | ||
436 | dst_release(&rt2->dst); | 433 | dst_release(&rt2->dst); |
@@ -442,7 +439,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, | |||
442 | goto relookup_failed; | 439 | goto relookup_failed; |
443 | 440 | ||
444 | rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst, | 441 | rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst, |
445 | flowi4_to_flowi(&fl4), NULL, | 442 | flowi4_to_flowi(fl4), NULL, |
446 | XFRM_LOOKUP_ICMP); | 443 | XFRM_LOOKUP_ICMP); |
447 | if (!IS_ERR(rt2)) { | 444 | if (!IS_ERR(rt2)) { |
448 | dst_release(&rt->dst); | 445 | dst_release(&rt->dst); |
@@ -481,6 +478,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
481 | struct icmp_bxm icmp_param; | 478 | struct icmp_bxm icmp_param; |
482 | struct rtable *rt = skb_rtable(skb_in); | 479 | struct rtable *rt = skb_rtable(skb_in); |
483 | struct ipcm_cookie ipc; | 480 | struct ipcm_cookie ipc; |
481 | struct flowi4 fl4; | ||
484 | __be32 saddr; | 482 | __be32 saddr; |
485 | u8 tos; | 483 | u8 tos; |
486 | struct net *net; | 484 | struct net *net; |
@@ -599,7 +597,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
599 | ipc.opt = &icmp_param.replyopts.opt; | 597 | ipc.opt = &icmp_param.replyopts.opt; |
600 | ipc.tx_flags = 0; | 598 | ipc.tx_flags = 0; |
601 | 599 | ||
602 | rt = icmp_route_lookup(net, skb_in, iph, saddr, tos, | 600 | rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, |
603 | type, code, &icmp_param); | 601 | type, code, &icmp_param); |
604 | if (IS_ERR(rt)) | 602 | if (IS_ERR(rt)) |
605 | goto out_unlock; | 603 | goto out_unlock; |
@@ -620,7 +618,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
620 | icmp_param.data_len = room; | 618 | icmp_param.data_len = room; |
621 | icmp_param.head_len = sizeof(struct icmphdr); | 619 | icmp_param.head_len = sizeof(struct icmphdr); |
622 | 620 | ||
623 | icmp_push_reply(&icmp_param, &ipc, &rt); | 621 | icmp_push_reply(&icmp_param, &fl4, &ipc, &rt); |
624 | ende: | 622 | ende: |
625 | ip_rt_put(rt); | 623 | ip_rt_put(rt); |
626 | out_unlock: | 624 | out_unlock: |