diff options
Diffstat (limited to 'net/ipv4/ipvs/ip_vs_ctl.c')
-rw-r--r-- | net/ipv4/ipvs/ip_vs_ctl.c | 523 |
1 files changed, 355 insertions, 168 deletions
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c index ede101eeec17..993a83fb0d56 100644 --- a/net/ipv4/ipvs/ip_vs_ctl.c +++ b/net/ipv4/ipvs/ip_vs_ctl.c | |||
@@ -35,6 +35,10 @@ | |||
35 | 35 | ||
36 | #include <net/net_namespace.h> | 36 | #include <net/net_namespace.h> |
37 | #include <net/ip.h> | 37 | #include <net/ip.h> |
38 | #ifdef CONFIG_IP_VS_IPV6 | ||
39 | #include <net/ipv6.h> | ||
40 | #include <net/ip6_route.h> | ||
41 | #endif | ||
38 | #include <net/route.h> | 42 | #include <net/route.h> |
39 | #include <net/sock.h> | 43 | #include <net/sock.h> |
40 | #include <net/genetlink.h> | 44 | #include <net/genetlink.h> |
@@ -91,6 +95,26 @@ int ip_vs_get_debug_level(void) | |||
91 | } | 95 | } |
92 | #endif | 96 | #endif |
93 | 97 | ||
98 | #ifdef CONFIG_IP_VS_IPV6 | ||
99 | /* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */ | ||
100 | static int __ip_vs_addr_is_local_v6(const struct in6_addr *addr) | ||
101 | { | ||
102 | struct rt6_info *rt; | ||
103 | struct flowi fl = { | ||
104 | .oif = 0, | ||
105 | .nl_u = { | ||
106 | .ip6_u = { | ||
107 | .daddr = *addr, | ||
108 | .saddr = { .s6_addr32 = {0, 0, 0, 0} }, } }, | ||
109 | }; | ||
110 | |||
111 | rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl); | ||
112 | if (rt && rt->rt6i_dev && (rt->rt6i_dev->flags & IFF_LOOPBACK)) | ||
113 | return 1; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | #endif | ||
94 | /* | 118 | /* |
95 | * update_defense_level is called from keventd and from sysctl, | 119 | * update_defense_level is called from keventd and from sysctl, |
96 | * so it needs to protect itself from softirqs | 120 | * so it needs to protect itself from softirqs |
@@ -282,11 +306,19 @@ static atomic_t ip_vs_nullsvc_counter = ATOMIC_INIT(0); | |||
282 | * Returns hash value for virtual service | 306 | * Returns hash value for virtual service |
283 | */ | 307 | */ |
284 | static __inline__ unsigned | 308 | static __inline__ unsigned |
285 | ip_vs_svc_hashkey(unsigned proto, __be32 addr, __be16 port) | 309 | ip_vs_svc_hashkey(int af, unsigned proto, const union nf_inet_addr *addr, |
310 | __be16 port) | ||
286 | { | 311 | { |
287 | register unsigned porth = ntohs(port); | 312 | register unsigned porth = ntohs(port); |
313 | __be32 addr_fold = addr->ip; | ||
314 | |||
315 | #ifdef CONFIG_IP_VS_IPV6 | ||
316 | if (af == AF_INET6) | ||
317 | addr_fold = addr->ip6[0]^addr->ip6[1]^ | ||
318 | addr->ip6[2]^addr->ip6[3]; | ||
319 | #endif | ||
288 | 320 | ||
289 | return (proto^ntohl(addr)^(porth>>IP_VS_SVC_TAB_BITS)^porth) | 321 | return (proto^ntohl(addr_fold)^(porth>>IP_VS_SVC_TAB_BITS)^porth) |
290 | & IP_VS_SVC_TAB_MASK; | 322 | & IP_VS_SVC_TAB_MASK; |
291 | } | 323 | } |
292 | 324 | ||
@@ -317,7 +349,8 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc) | |||
317 | /* | 349 | /* |
318 | * Hash it by <protocol,addr,port> in ip_vs_svc_table | 350 | * Hash it by <protocol,addr,port> in ip_vs_svc_table |
319 | */ | 351 | */ |
320 | hash = ip_vs_svc_hashkey(svc->protocol, svc->addr, svc->port); | 352 | hash = ip_vs_svc_hashkey(svc->af, svc->protocol, &svc->addr, |
353 | svc->port); | ||
321 | list_add(&svc->s_list, &ip_vs_svc_table[hash]); | 354 | list_add(&svc->s_list, &ip_vs_svc_table[hash]); |
322 | } else { | 355 | } else { |
323 | /* | 356 | /* |
@@ -363,17 +396,19 @@ static int ip_vs_svc_unhash(struct ip_vs_service *svc) | |||
363 | /* | 396 | /* |
364 | * Get service by {proto,addr,port} in the service table. | 397 | * Get service by {proto,addr,port} in the service table. |
365 | */ | 398 | */ |
366 | static __inline__ struct ip_vs_service * | 399 | static inline struct ip_vs_service * |
367 | __ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport) | 400 | __ip_vs_service_get(int af, __u16 protocol, const union nf_inet_addr *vaddr, |
401 | __be16 vport) | ||
368 | { | 402 | { |
369 | unsigned hash; | 403 | unsigned hash; |
370 | struct ip_vs_service *svc; | 404 | struct ip_vs_service *svc; |
371 | 405 | ||
372 | /* Check for "full" addressed entries */ | 406 | /* Check for "full" addressed entries */ |
373 | hash = ip_vs_svc_hashkey(protocol, vaddr, vport); | 407 | hash = ip_vs_svc_hashkey(af, protocol, vaddr, vport); |
374 | 408 | ||
375 | list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){ | 409 | list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){ |
376 | if ((svc->addr == vaddr) | 410 | if ((svc->af == af) |
411 | && ip_vs_addr_equal(af, &svc->addr, vaddr) | ||
377 | && (svc->port == vport) | 412 | && (svc->port == vport) |
378 | && (svc->protocol == protocol)) { | 413 | && (svc->protocol == protocol)) { |
379 | /* HIT */ | 414 | /* HIT */ |
@@ -389,7 +424,8 @@ __ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport) | |||
389 | /* | 424 | /* |
390 | * Get service by {fwmark} in the service table. | 425 | * Get service by {fwmark} in the service table. |
391 | */ | 426 | */ |
392 | static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark) | 427 | static inline struct ip_vs_service * |
428 | __ip_vs_svc_fwm_get(int af, __u32 fwmark) | ||
393 | { | 429 | { |
394 | unsigned hash; | 430 | unsigned hash; |
395 | struct ip_vs_service *svc; | 431 | struct ip_vs_service *svc; |
@@ -398,7 +434,7 @@ static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark) | |||
398 | hash = ip_vs_svc_fwm_hashkey(fwmark); | 434 | hash = ip_vs_svc_fwm_hashkey(fwmark); |
399 | 435 | ||
400 | list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) { | 436 | list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) { |
401 | if (svc->fwmark == fwmark) { | 437 | if (svc->fwmark == fwmark && svc->af == af) { |
402 | /* HIT */ | 438 | /* HIT */ |
403 | atomic_inc(&svc->usecnt); | 439 | atomic_inc(&svc->usecnt); |
404 | return svc; | 440 | return svc; |
@@ -409,7 +445,8 @@ static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark) | |||
409 | } | 445 | } |
410 | 446 | ||
411 | struct ip_vs_service * | 447 | struct ip_vs_service * |
412 | ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport) | 448 | ip_vs_service_get(int af, __u32 fwmark, __u16 protocol, |
449 | const union nf_inet_addr *vaddr, __be16 vport) | ||
413 | { | 450 | { |
414 | struct ip_vs_service *svc; | 451 | struct ip_vs_service *svc; |
415 | 452 | ||
@@ -418,14 +455,14 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport) | |||
418 | /* | 455 | /* |
419 | * Check the table hashed by fwmark first | 456 | * Check the table hashed by fwmark first |
420 | */ | 457 | */ |
421 | if (fwmark && (svc = __ip_vs_svc_fwm_get(fwmark))) | 458 | if (fwmark && (svc = __ip_vs_svc_fwm_get(af, fwmark))) |
422 | goto out; | 459 | goto out; |
423 | 460 | ||
424 | /* | 461 | /* |
425 | * Check the table hashed by <protocol,addr,port> | 462 | * Check the table hashed by <protocol,addr,port> |
426 | * for "full" addressed entries | 463 | * for "full" addressed entries |
427 | */ | 464 | */ |
428 | svc = __ip_vs_service_get(protocol, vaddr, vport); | 465 | svc = __ip_vs_service_get(af, protocol, vaddr, vport); |
429 | 466 | ||
430 | if (svc == NULL | 467 | if (svc == NULL |
431 | && protocol == IPPROTO_TCP | 468 | && protocol == IPPROTO_TCP |
@@ -435,7 +472,7 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport) | |||
435 | * Check if ftp service entry exists, the packet | 472 | * Check if ftp service entry exists, the packet |
436 | * might belong to FTP data connections. | 473 | * might belong to FTP data connections. |
437 | */ | 474 | */ |
438 | svc = __ip_vs_service_get(protocol, vaddr, FTPPORT); | 475 | svc = __ip_vs_service_get(af, protocol, vaddr, FTPPORT); |
439 | } | 476 | } |
440 | 477 | ||
441 | if (svc == NULL | 478 | if (svc == NULL |
@@ -443,16 +480,16 @@ ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport) | |||
443 | /* | 480 | /* |
444 | * Check if the catch-all port (port zero) exists | 481 | * Check if the catch-all port (port zero) exists |
445 | */ | 482 | */ |
446 | svc = __ip_vs_service_get(protocol, vaddr, 0); | 483 | svc = __ip_vs_service_get(af, protocol, vaddr, 0); |
447 | } | 484 | } |
448 | 485 | ||
449 | out: | 486 | out: |
450 | read_unlock(&__ip_vs_svc_lock); | 487 | read_unlock(&__ip_vs_svc_lock); |
451 | 488 | ||
452 | IP_VS_DBG(9, "lookup service: fwm %u %s %u.%u.%u.%u:%u %s\n", | 489 | IP_VS_DBG_BUF(9, "lookup service: fwm %u %s %s:%u %s\n", |
453 | fwmark, ip_vs_proto_name(protocol), | 490 | fwmark, ip_vs_proto_name(protocol), |
454 | NIPQUAD(vaddr), ntohs(vport), | 491 | IP_VS_DBG_ADDR(af, vaddr), ntohs(vport), |
455 | svc?"hit":"not hit"); | 492 | svc ? "hit" : "not hit"); |
456 | 493 | ||
457 | return svc; | 494 | return svc; |
458 | } | 495 | } |
@@ -479,11 +516,20 @@ __ip_vs_unbind_svc(struct ip_vs_dest *dest) | |||
479 | /* | 516 | /* |
480 | * Returns hash value for real service | 517 | * Returns hash value for real service |
481 | */ | 518 | */ |
482 | static __inline__ unsigned ip_vs_rs_hashkey(__be32 addr, __be16 port) | 519 | static inline unsigned ip_vs_rs_hashkey(int af, |
520 | const union nf_inet_addr *addr, | ||
521 | __be16 port) | ||
483 | { | 522 | { |
484 | register unsigned porth = ntohs(port); | 523 | register unsigned porth = ntohs(port); |
524 | __be32 addr_fold = addr->ip; | ||
525 | |||
526 | #ifdef CONFIG_IP_VS_IPV6 | ||
527 | if (af == AF_INET6) | ||
528 | addr_fold = addr->ip6[0]^addr->ip6[1]^ | ||
529 | addr->ip6[2]^addr->ip6[3]; | ||
530 | #endif | ||
485 | 531 | ||
486 | return (ntohl(addr)^(porth>>IP_VS_RTAB_BITS)^porth) | 532 | return (ntohl(addr_fold)^(porth>>IP_VS_RTAB_BITS)^porth) |
487 | & IP_VS_RTAB_MASK; | 533 | & IP_VS_RTAB_MASK; |
488 | } | 534 | } |
489 | 535 | ||
@@ -503,7 +549,8 @@ static int ip_vs_rs_hash(struct ip_vs_dest *dest) | |||
503 | * Hash by proto,addr,port, | 549 | * Hash by proto,addr,port, |
504 | * which are the parameters of the real service. | 550 | * which are the parameters of the real service. |
505 | */ | 551 | */ |
506 | hash = ip_vs_rs_hashkey(dest->addr, dest->port); | 552 | hash = ip_vs_rs_hashkey(dest->af, &dest->addr, dest->port); |
553 | |||
507 | list_add(&dest->d_list, &ip_vs_rtable[hash]); | 554 | list_add(&dest->d_list, &ip_vs_rtable[hash]); |
508 | 555 | ||
509 | return 1; | 556 | return 1; |
@@ -530,7 +577,9 @@ static int ip_vs_rs_unhash(struct ip_vs_dest *dest) | |||
530 | * Lookup real service by <proto,addr,port> in the real service table. | 577 | * Lookup real service by <proto,addr,port> in the real service table. |
531 | */ | 578 | */ |
532 | struct ip_vs_dest * | 579 | struct ip_vs_dest * |
533 | ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport) | 580 | ip_vs_lookup_real_service(int af, __u16 protocol, |
581 | const union nf_inet_addr *daddr, | ||
582 | __be16 dport) | ||
534 | { | 583 | { |
535 | unsigned hash; | 584 | unsigned hash; |
536 | struct ip_vs_dest *dest; | 585 | struct ip_vs_dest *dest; |
@@ -539,11 +588,12 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport) | |||
539 | * Check for "full" addressed entries | 588 | * Check for "full" addressed entries |
540 | * Return the first found entry | 589 | * Return the first found entry |
541 | */ | 590 | */ |
542 | hash = ip_vs_rs_hashkey(daddr, dport); | 591 | hash = ip_vs_rs_hashkey(af, daddr, dport); |
543 | 592 | ||
544 | read_lock(&__ip_vs_rs_lock); | 593 | read_lock(&__ip_vs_rs_lock); |
545 | list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) { | 594 | list_for_each_entry(dest, &ip_vs_rtable[hash], d_list) { |
546 | if ((dest->addr == daddr) | 595 | if ((dest->af == af) |
596 | && ip_vs_addr_equal(af, &dest->addr, daddr) | ||
547 | && (dest->port == dport) | 597 | && (dest->port == dport) |
548 | && ((dest->protocol == protocol) || | 598 | && ((dest->protocol == protocol) || |
549 | dest->vfwmark)) { | 599 | dest->vfwmark)) { |
@@ -561,7 +611,8 @@ ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport) | |||
561 | * Lookup destination by {addr,port} in the given service | 611 | * Lookup destination by {addr,port} in the given service |
562 | */ | 612 | */ |
563 | static struct ip_vs_dest * | 613 | static struct ip_vs_dest * |
564 | ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport) | 614 | ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr, |
615 | __be16 dport) | ||
565 | { | 616 | { |
566 | struct ip_vs_dest *dest; | 617 | struct ip_vs_dest *dest; |
567 | 618 | ||
@@ -569,7 +620,9 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport) | |||
569 | * Find the destination for the given service | 620 | * Find the destination for the given service |
570 | */ | 621 | */ |
571 | list_for_each_entry(dest, &svc->destinations, n_list) { | 622 | list_for_each_entry(dest, &svc->destinations, n_list) { |
572 | if ((dest->addr == daddr) && (dest->port == dport)) { | 623 | if ((dest->af == svc->af) |
624 | && ip_vs_addr_equal(svc->af, &dest->addr, daddr) | ||
625 | && (dest->port == dport)) { | ||
573 | /* HIT */ | 626 | /* HIT */ |
574 | return dest; | 627 | return dest; |
575 | } | 628 | } |
@@ -588,13 +641,15 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport) | |||
588 | * ip_vs_lookup_real_service() looked promissing, but | 641 | * ip_vs_lookup_real_service() looked promissing, but |
589 | * seems not working as expected. | 642 | * seems not working as expected. |
590 | */ | 643 | */ |
591 | struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport, | 644 | struct ip_vs_dest *ip_vs_find_dest(int af, const union nf_inet_addr *daddr, |
592 | __be32 vaddr, __be16 vport, __u16 protocol) | 645 | __be16 dport, |
646 | const union nf_inet_addr *vaddr, | ||
647 | __be16 vport, __u16 protocol) | ||
593 | { | 648 | { |
594 | struct ip_vs_dest *dest; | 649 | struct ip_vs_dest *dest; |
595 | struct ip_vs_service *svc; | 650 | struct ip_vs_service *svc; |
596 | 651 | ||
597 | svc = ip_vs_service_get(0, protocol, vaddr, vport); | 652 | svc = ip_vs_service_get(af, 0, protocol, vaddr, vport); |
598 | if (!svc) | 653 | if (!svc) |
599 | return NULL; | 654 | return NULL; |
600 | dest = ip_vs_lookup_dest(svc, daddr, dport); | 655 | dest = ip_vs_lookup_dest(svc, daddr, dport); |
@@ -615,7 +670,8 @@ struct ip_vs_dest *ip_vs_find_dest(__be32 daddr, __be16 dport, | |||
615 | * scheduling. | 670 | * scheduling. |
616 | */ | 671 | */ |
617 | static struct ip_vs_dest * | 672 | static struct ip_vs_dest * |
618 | ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport) | 673 | ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr, |
674 | __be16 dport) | ||
619 | { | 675 | { |
620 | struct ip_vs_dest *dest, *nxt; | 676 | struct ip_vs_dest *dest, *nxt; |
621 | 677 | ||
@@ -623,17 +679,19 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport) | |||
623 | * Find the destination in trash | 679 | * Find the destination in trash |
624 | */ | 680 | */ |
625 | list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) { | 681 | list_for_each_entry_safe(dest, nxt, &ip_vs_dest_trash, n_list) { |
626 | IP_VS_DBG(3, "Destination %u/%u.%u.%u.%u:%u still in trash, " | 682 | IP_VS_DBG_BUF(3, "Destination %u/%s:%u still in trash, " |
627 | "dest->refcnt=%d\n", | 683 | "dest->refcnt=%d\n", |
628 | dest->vfwmark, | 684 | dest->vfwmark, |
629 | NIPQUAD(dest->addr), ntohs(dest->port), | 685 | IP_VS_DBG_ADDR(svc->af, &dest->addr), |
630 | atomic_read(&dest->refcnt)); | 686 | ntohs(dest->port), |
631 | if (dest->addr == daddr && | 687 | atomic_read(&dest->refcnt)); |
688 | if (dest->af == svc->af && | ||
689 | ip_vs_addr_equal(svc->af, &dest->addr, daddr) && | ||
632 | dest->port == dport && | 690 | dest->port == dport && |
633 | dest->vfwmark == svc->fwmark && | 691 | dest->vfwmark == svc->fwmark && |
634 | dest->protocol == svc->protocol && | 692 | dest->protocol == svc->protocol && |
635 | (svc->fwmark || | 693 | (svc->fwmark || |
636 | (dest->vaddr == svc->addr && | 694 | (ip_vs_addr_equal(svc->af, &dest->vaddr, &svc->addr) && |
637 | dest->vport == svc->port))) { | 695 | dest->vport == svc->port))) { |
638 | /* HIT */ | 696 | /* HIT */ |
639 | return dest; | 697 | return dest; |
@@ -643,10 +701,11 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport) | |||
643 | * Try to purge the destination from trash if not referenced | 701 | * Try to purge the destination from trash if not referenced |
644 | */ | 702 | */ |
645 | if (atomic_read(&dest->refcnt) == 1) { | 703 | if (atomic_read(&dest->refcnt) == 1) { |
646 | IP_VS_DBG(3, "Removing destination %u/%u.%u.%u.%u:%u " | 704 | IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u " |
647 | "from trash\n", | 705 | "from trash\n", |
648 | dest->vfwmark, | 706 | dest->vfwmark, |
649 | NIPQUAD(dest->addr), ntohs(dest->port)); | 707 | IP_VS_DBG_ADDR(svc->af, &dest->addr), |
708 | ntohs(dest->port)); | ||
650 | list_del(&dest->n_list); | 709 | list_del(&dest->n_list); |
651 | ip_vs_dst_reset(dest); | 710 | ip_vs_dst_reset(dest); |
652 | __ip_vs_unbind_svc(dest); | 711 | __ip_vs_unbind_svc(dest); |
@@ -685,18 +744,7 @@ ip_vs_zero_stats(struct ip_vs_stats *stats) | |||
685 | { | 744 | { |
686 | spin_lock_bh(&stats->lock); | 745 | spin_lock_bh(&stats->lock); |
687 | 746 | ||
688 | stats->conns = 0; | 747 | memset(&stats->ustats, 0, sizeof(stats->ustats)); |
689 | stats->inpkts = 0; | ||
690 | stats->outpkts = 0; | ||
691 | stats->inbytes = 0; | ||
692 | stats->outbytes = 0; | ||
693 | |||
694 | stats->cps = 0; | ||
695 | stats->inpps = 0; | ||
696 | stats->outpps = 0; | ||
697 | stats->inbps = 0; | ||
698 | stats->outbps = 0; | ||
699 | |||
700 | ip_vs_zero_estimator(stats); | 748 | ip_vs_zero_estimator(stats); |
701 | 749 | ||
702 | spin_unlock_bh(&stats->lock); | 750 | spin_unlock_bh(&stats->lock); |
@@ -707,7 +755,7 @@ ip_vs_zero_stats(struct ip_vs_stats *stats) | |||
707 | */ | 755 | */ |
708 | static void | 756 | static void |
709 | __ip_vs_update_dest(struct ip_vs_service *svc, | 757 | __ip_vs_update_dest(struct ip_vs_service *svc, |
710 | struct ip_vs_dest *dest, struct ip_vs_dest_user *udest) | 758 | struct ip_vs_dest *dest, struct ip_vs_dest_user_kern *udest) |
711 | { | 759 | { |
712 | int conn_flags; | 760 | int conn_flags; |
713 | 761 | ||
@@ -716,10 +764,18 @@ __ip_vs_update_dest(struct ip_vs_service *svc, | |||
716 | conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE; | 764 | conn_flags = udest->conn_flags | IP_VS_CONN_F_INACTIVE; |
717 | 765 | ||
718 | /* check if local node and update the flags */ | 766 | /* check if local node and update the flags */ |
719 | if (inet_addr_type(&init_net, udest->addr) == RTN_LOCAL) { | 767 | #ifdef CONFIG_IP_VS_IPV6 |
720 | conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK) | 768 | if (svc->af == AF_INET6) { |
721 | | IP_VS_CONN_F_LOCALNODE; | 769 | if (__ip_vs_addr_is_local_v6(&udest->addr.in6)) { |
722 | } | 770 | conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK) |
771 | | IP_VS_CONN_F_LOCALNODE; | ||
772 | } | ||
773 | } else | ||
774 | #endif | ||
775 | if (inet_addr_type(&init_net, udest->addr.ip) == RTN_LOCAL) { | ||
776 | conn_flags = (conn_flags & ~IP_VS_CONN_F_FWD_MASK) | ||
777 | | IP_VS_CONN_F_LOCALNODE; | ||
778 | } | ||
723 | 779 | ||
724 | /* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */ | 780 | /* set the IP_VS_CONN_F_NOOUTPUT flag if not masquerading/NAT */ |
725 | if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) { | 781 | if ((conn_flags & IP_VS_CONN_F_FWD_MASK) != 0) { |
@@ -760,7 +816,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc, | |||
760 | * Create a destination for the given service | 816 | * Create a destination for the given service |
761 | */ | 817 | */ |
762 | static int | 818 | static int |
763 | ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest, | 819 | ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest, |
764 | struct ip_vs_dest **dest_p) | 820 | struct ip_vs_dest **dest_p) |
765 | { | 821 | { |
766 | struct ip_vs_dest *dest; | 822 | struct ip_vs_dest *dest; |
@@ -768,9 +824,20 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest, | |||
768 | 824 | ||
769 | EnterFunction(2); | 825 | EnterFunction(2); |
770 | 826 | ||
771 | atype = inet_addr_type(&init_net, udest->addr); | 827 | #ifdef CONFIG_IP_VS_IPV6 |
772 | if (atype != RTN_LOCAL && atype != RTN_UNICAST) | 828 | if (svc->af == AF_INET6) { |
773 | return -EINVAL; | 829 | atype = ipv6_addr_type(&udest->addr.in6); |
830 | if ((!(atype & IPV6_ADDR_UNICAST) || | ||
831 | atype & IPV6_ADDR_LINKLOCAL) && | ||
832 | !__ip_vs_addr_is_local_v6(&udest->addr.in6)) | ||
833 | return -EINVAL; | ||
834 | } else | ||
835 | #endif | ||
836 | { | ||
837 | atype = inet_addr_type(&init_net, udest->addr.ip); | ||
838 | if (atype != RTN_LOCAL && atype != RTN_UNICAST) | ||
839 | return -EINVAL; | ||
840 | } | ||
774 | 841 | ||
775 | dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC); | 842 | dest = kzalloc(sizeof(struct ip_vs_dest), GFP_ATOMIC); |
776 | if (dest == NULL) { | 843 | if (dest == NULL) { |
@@ -778,11 +845,12 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest, | |||
778 | return -ENOMEM; | 845 | return -ENOMEM; |
779 | } | 846 | } |
780 | 847 | ||
848 | dest->af = svc->af; | ||
781 | dest->protocol = svc->protocol; | 849 | dest->protocol = svc->protocol; |
782 | dest->vaddr = svc->addr; | 850 | dest->vaddr = svc->addr; |
783 | dest->vport = svc->port; | 851 | dest->vport = svc->port; |
784 | dest->vfwmark = svc->fwmark; | 852 | dest->vfwmark = svc->fwmark; |
785 | dest->addr = udest->addr; | 853 | ip_vs_addr_copy(svc->af, &dest->addr, &udest->addr); |
786 | dest->port = udest->port; | 854 | dest->port = udest->port; |
787 | 855 | ||
788 | atomic_set(&dest->activeconns, 0); | 856 | atomic_set(&dest->activeconns, 0); |
@@ -807,10 +875,10 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest, | |||
807 | * Add a destination into an existing service | 875 | * Add a destination into an existing service |
808 | */ | 876 | */ |
809 | static int | 877 | static int |
810 | ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest) | 878 | ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) |
811 | { | 879 | { |
812 | struct ip_vs_dest *dest; | 880 | struct ip_vs_dest *dest; |
813 | __be32 daddr = udest->addr; | 881 | union nf_inet_addr daddr; |
814 | __be16 dport = udest->port; | 882 | __be16 dport = udest->port; |
815 | int ret; | 883 | int ret; |
816 | 884 | ||
@@ -827,10 +895,13 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest) | |||
827 | return -ERANGE; | 895 | return -ERANGE; |
828 | } | 896 | } |
829 | 897 | ||
898 | ip_vs_addr_copy(svc->af, &daddr, &udest->addr); | ||
899 | |||
830 | /* | 900 | /* |
831 | * Check if the dest already exists in the list | 901 | * Check if the dest already exists in the list |
832 | */ | 902 | */ |
833 | dest = ip_vs_lookup_dest(svc, daddr, dport); | 903 | dest = ip_vs_lookup_dest(svc, &daddr, dport); |
904 | |||
834 | if (dest != NULL) { | 905 | if (dest != NULL) { |
835 | IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n"); | 906 | IP_VS_DBG(1, "ip_vs_add_dest(): dest already exists\n"); |
836 | return -EEXIST; | 907 | return -EEXIST; |
@@ -840,15 +911,17 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest) | |||
840 | * Check if the dest already exists in the trash and | 911 | * Check if the dest already exists in the trash and |
841 | * is from the same service | 912 | * is from the same service |
842 | */ | 913 | */ |
843 | dest = ip_vs_trash_get_dest(svc, daddr, dport); | 914 | dest = ip_vs_trash_get_dest(svc, &daddr, dport); |
915 | |||
844 | if (dest != NULL) { | 916 | if (dest != NULL) { |
845 | IP_VS_DBG(3, "Get destination %u.%u.%u.%u:%u from trash, " | 917 | IP_VS_DBG_BUF(3, "Get destination %s:%u from trash, " |
846 | "dest->refcnt=%d, service %u/%u.%u.%u.%u:%u\n", | 918 | "dest->refcnt=%d, service %u/%s:%u\n", |
847 | NIPQUAD(daddr), ntohs(dport), | 919 | IP_VS_DBG_ADDR(svc->af, &daddr), ntohs(dport), |
848 | atomic_read(&dest->refcnt), | 920 | atomic_read(&dest->refcnt), |
849 | dest->vfwmark, | 921 | dest->vfwmark, |
850 | NIPQUAD(dest->vaddr), | 922 | IP_VS_DBG_ADDR(svc->af, &dest->vaddr), |
851 | ntohs(dest->vport)); | 923 | ntohs(dest->vport)); |
924 | |||
852 | __ip_vs_update_dest(svc, dest, udest); | 925 | __ip_vs_update_dest(svc, dest, udest); |
853 | 926 | ||
854 | /* | 927 | /* |
@@ -915,10 +988,10 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest) | |||
915 | * Edit a destination in the given service | 988 | * Edit a destination in the given service |
916 | */ | 989 | */ |
917 | static int | 990 | static int |
918 | ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest) | 991 | ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) |
919 | { | 992 | { |
920 | struct ip_vs_dest *dest; | 993 | struct ip_vs_dest *dest; |
921 | __be32 daddr = udest->addr; | 994 | union nf_inet_addr daddr; |
922 | __be16 dport = udest->port; | 995 | __be16 dport = udest->port; |
923 | 996 | ||
924 | EnterFunction(2); | 997 | EnterFunction(2); |
@@ -934,10 +1007,13 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest) | |||
934 | return -ERANGE; | 1007 | return -ERANGE; |
935 | } | 1008 | } |
936 | 1009 | ||
1010 | ip_vs_addr_copy(svc->af, &daddr, &udest->addr); | ||
1011 | |||
937 | /* | 1012 | /* |
938 | * Lookup the destination list | 1013 | * Lookup the destination list |
939 | */ | 1014 | */ |
940 | dest = ip_vs_lookup_dest(svc, daddr, dport); | 1015 | dest = ip_vs_lookup_dest(svc, &daddr, dport); |
1016 | |||
941 | if (dest == NULL) { | 1017 | if (dest == NULL) { |
942 | IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n"); | 1018 | IP_VS_DBG(1, "ip_vs_edit_dest(): dest doesn't exist\n"); |
943 | return -ENOENT; | 1019 | return -ENOENT; |
@@ -991,10 +1067,11 @@ static void __ip_vs_del_dest(struct ip_vs_dest *dest) | |||
991 | atomic_dec(&dest->svc->refcnt); | 1067 | atomic_dec(&dest->svc->refcnt); |
992 | kfree(dest); | 1068 | kfree(dest); |
993 | } else { | 1069 | } else { |
994 | IP_VS_DBG(3, "Moving dest %u.%u.%u.%u:%u into trash, " | 1070 | IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, " |
995 | "dest->refcnt=%d\n", | 1071 | "dest->refcnt=%d\n", |
996 | NIPQUAD(dest->addr), ntohs(dest->port), | 1072 | IP_VS_DBG_ADDR(dest->af, &dest->addr), |
997 | atomic_read(&dest->refcnt)); | 1073 | ntohs(dest->port), |
1074 | atomic_read(&dest->refcnt)); | ||
998 | list_add(&dest->n_list, &ip_vs_dest_trash); | 1075 | list_add(&dest->n_list, &ip_vs_dest_trash); |
999 | atomic_inc(&dest->refcnt); | 1076 | atomic_inc(&dest->refcnt); |
1000 | } | 1077 | } |
@@ -1028,15 +1105,15 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc, | |||
1028 | * Delete a destination server in the given service | 1105 | * Delete a destination server in the given service |
1029 | */ | 1106 | */ |
1030 | static int | 1107 | static int |
1031 | ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest) | 1108 | ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) |
1032 | { | 1109 | { |
1033 | struct ip_vs_dest *dest; | 1110 | struct ip_vs_dest *dest; |
1034 | __be32 daddr = udest->addr; | ||
1035 | __be16 dport = udest->port; | 1111 | __be16 dport = udest->port; |
1036 | 1112 | ||
1037 | EnterFunction(2); | 1113 | EnterFunction(2); |
1038 | 1114 | ||
1039 | dest = ip_vs_lookup_dest(svc, daddr, dport); | 1115 | dest = ip_vs_lookup_dest(svc, &udest->addr, dport); |
1116 | |||
1040 | if (dest == NULL) { | 1117 | if (dest == NULL) { |
1041 | IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n"); | 1118 | IP_VS_DBG(1, "ip_vs_del_dest(): destination not found!\n"); |
1042 | return -ENOENT; | 1119 | return -ENOENT; |
@@ -1071,7 +1148,8 @@ ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest) | |||
1071 | * Add a service into the service hash table | 1148 | * Add a service into the service hash table |
1072 | */ | 1149 | */ |
1073 | static int | 1150 | static int |
1074 | ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p) | 1151 | ip_vs_add_service(struct ip_vs_service_user_kern *u, |
1152 | struct ip_vs_service **svc_p) | ||
1075 | { | 1153 | { |
1076 | int ret = 0; | 1154 | int ret = 0; |
1077 | struct ip_vs_scheduler *sched = NULL; | 1155 | struct ip_vs_scheduler *sched = NULL; |
@@ -1089,6 +1167,19 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p) | |||
1089 | goto out_mod_dec; | 1167 | goto out_mod_dec; |
1090 | } | 1168 | } |
1091 | 1169 | ||
1170 | #ifdef CONFIG_IP_VS_IPV6 | ||
1171 | if (u->af == AF_INET6) { | ||
1172 | if (!sched->supports_ipv6) { | ||
1173 | ret = -EAFNOSUPPORT; | ||
1174 | goto out_err; | ||
1175 | } | ||
1176 | if ((u->netmask < 1) || (u->netmask > 128)) { | ||
1177 | ret = -EINVAL; | ||
1178 | goto out_err; | ||
1179 | } | ||
1180 | } | ||
1181 | #endif | ||
1182 | |||
1092 | svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC); | 1183 | svc = kzalloc(sizeof(struct ip_vs_service), GFP_ATOMIC); |
1093 | if (svc == NULL) { | 1184 | if (svc == NULL) { |
1094 | IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n"); | 1185 | IP_VS_DBG(1, "ip_vs_add_service: kmalloc failed.\n"); |
@@ -1100,8 +1191,9 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p) | |||
1100 | atomic_set(&svc->usecnt, 1); | 1191 | atomic_set(&svc->usecnt, 1); |
1101 | atomic_set(&svc->refcnt, 0); | 1192 | atomic_set(&svc->refcnt, 0); |
1102 | 1193 | ||
1194 | svc->af = u->af; | ||
1103 | svc->protocol = u->protocol; | 1195 | svc->protocol = u->protocol; |
1104 | svc->addr = u->addr; | 1196 | ip_vs_addr_copy(svc->af, &svc->addr, &u->addr); |
1105 | svc->port = u->port; | 1197 | svc->port = u->port; |
1106 | svc->fwmark = u->fwmark; | 1198 | svc->fwmark = u->fwmark; |
1107 | svc->flags = u->flags; | 1199 | svc->flags = u->flags; |
@@ -1125,7 +1217,10 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p) | |||
1125 | atomic_inc(&ip_vs_nullsvc_counter); | 1217 | atomic_inc(&ip_vs_nullsvc_counter); |
1126 | 1218 | ||
1127 | ip_vs_new_estimator(&svc->stats); | 1219 | ip_vs_new_estimator(&svc->stats); |
1128 | ip_vs_num_services++; | 1220 | |
1221 | /* Count only IPv4 services for old get/setsockopt interface */ | ||
1222 | if (svc->af == AF_INET) | ||
1223 | ip_vs_num_services++; | ||
1129 | 1224 | ||
1130 | /* Hash the service into the service table */ | 1225 | /* Hash the service into the service table */ |
1131 | write_lock_bh(&__ip_vs_svc_lock); | 1226 | write_lock_bh(&__ip_vs_svc_lock); |
@@ -1160,7 +1255,7 @@ ip_vs_add_service(struct ip_vs_service_user *u, struct ip_vs_service **svc_p) | |||
1160 | * Edit a service and bind it with a new scheduler | 1255 | * Edit a service and bind it with a new scheduler |
1161 | */ | 1256 | */ |
1162 | static int | 1257 | static int |
1163 | ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user *u) | 1258 | ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) |
1164 | { | 1259 | { |
1165 | struct ip_vs_scheduler *sched, *old_sched; | 1260 | struct ip_vs_scheduler *sched, *old_sched; |
1166 | int ret = 0; | 1261 | int ret = 0; |
@@ -1176,6 +1271,19 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user *u) | |||
1176 | } | 1271 | } |
1177 | old_sched = sched; | 1272 | old_sched = sched; |
1178 | 1273 | ||
1274 | #ifdef CONFIG_IP_VS_IPV6 | ||
1275 | if (u->af == AF_INET6) { | ||
1276 | if (!sched->supports_ipv6) { | ||
1277 | ret = -EAFNOSUPPORT; | ||
1278 | goto out; | ||
1279 | } | ||
1280 | if ((u->netmask < 1) || (u->netmask > 128)) { | ||
1281 | ret = -EINVAL; | ||
1282 | goto out; | ||
1283 | } | ||
1284 | } | ||
1285 | #endif | ||
1286 | |||
1179 | write_lock_bh(&__ip_vs_svc_lock); | 1287 | write_lock_bh(&__ip_vs_svc_lock); |
1180 | 1288 | ||
1181 | /* | 1289 | /* |
@@ -1240,7 +1348,10 @@ static void __ip_vs_del_service(struct ip_vs_service *svc) | |||
1240 | struct ip_vs_dest *dest, *nxt; | 1348 | struct ip_vs_dest *dest, *nxt; |
1241 | struct ip_vs_scheduler *old_sched; | 1349 | struct ip_vs_scheduler *old_sched; |
1242 | 1350 | ||
1243 | ip_vs_num_services--; | 1351 | /* Count only IPv4 services for old get/setsockopt interface */ |
1352 | if (svc->af == AF_INET) | ||
1353 | ip_vs_num_services--; | ||
1354 | |||
1244 | ip_vs_kill_estimator(&svc->stats); | 1355 | ip_vs_kill_estimator(&svc->stats); |
1245 | 1356 | ||
1246 | /* Unbind scheduler */ | 1357 | /* Unbind scheduler */ |
@@ -1748,15 +1859,25 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v) | |||
1748 | const struct ip_vs_iter *iter = seq->private; | 1859 | const struct ip_vs_iter *iter = seq->private; |
1749 | const struct ip_vs_dest *dest; | 1860 | const struct ip_vs_dest *dest; |
1750 | 1861 | ||
1751 | if (iter->table == ip_vs_svc_table) | 1862 | if (iter->table == ip_vs_svc_table) { |
1752 | seq_printf(seq, "%s %08X:%04X %s ", | 1863 | #ifdef CONFIG_IP_VS_IPV6 |
1753 | ip_vs_proto_name(svc->protocol), | 1864 | if (svc->af == AF_INET6) |
1754 | ntohl(svc->addr), | 1865 | seq_printf(seq, "%s [" NIP6_FMT "]:%04X %s ", |
1755 | ntohs(svc->port), | 1866 | ip_vs_proto_name(svc->protocol), |
1756 | svc->scheduler->name); | 1867 | NIP6(svc->addr.in6), |
1757 | else | 1868 | ntohs(svc->port), |
1869 | svc->scheduler->name); | ||
1870 | else | ||
1871 | #endif | ||
1872 | seq_printf(seq, "%s %08X:%04X %s ", | ||
1873 | ip_vs_proto_name(svc->protocol), | ||
1874 | ntohl(svc->addr.ip), | ||
1875 | ntohs(svc->port), | ||
1876 | svc->scheduler->name); | ||
1877 | } else { | ||
1758 | seq_printf(seq, "FWM %08X %s ", | 1878 | seq_printf(seq, "FWM %08X %s ", |
1759 | svc->fwmark, svc->scheduler->name); | 1879 | svc->fwmark, svc->scheduler->name); |
1880 | } | ||
1760 | 1881 | ||
1761 | if (svc->flags & IP_VS_SVC_F_PERSISTENT) | 1882 | if (svc->flags & IP_VS_SVC_F_PERSISTENT) |
1762 | seq_printf(seq, "persistent %d %08X\n", | 1883 | seq_printf(seq, "persistent %d %08X\n", |
@@ -1766,13 +1887,29 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v) | |||
1766 | seq_putc(seq, '\n'); | 1887 | seq_putc(seq, '\n'); |
1767 | 1888 | ||
1768 | list_for_each_entry(dest, &svc->destinations, n_list) { | 1889 | list_for_each_entry(dest, &svc->destinations, n_list) { |
1769 | seq_printf(seq, | 1890 | #ifdef CONFIG_IP_VS_IPV6 |
1770 | " -> %08X:%04X %-7s %-6d %-10d %-10d\n", | 1891 | if (dest->af == AF_INET6) |
1771 | ntohl(dest->addr), ntohs(dest->port), | 1892 | seq_printf(seq, |
1772 | ip_vs_fwd_name(atomic_read(&dest->conn_flags)), | 1893 | " -> [" NIP6_FMT "]:%04X" |
1773 | atomic_read(&dest->weight), | 1894 | " %-7s %-6d %-10d %-10d\n", |
1774 | atomic_read(&dest->activeconns), | 1895 | NIP6(dest->addr.in6), |
1775 | atomic_read(&dest->inactconns)); | 1896 | ntohs(dest->port), |
1897 | ip_vs_fwd_name(atomic_read(&dest->conn_flags)), | ||
1898 | atomic_read(&dest->weight), | ||
1899 | atomic_read(&dest->activeconns), | ||
1900 | atomic_read(&dest->inactconns)); | ||
1901 | else | ||
1902 | #endif | ||
1903 | seq_printf(seq, | ||
1904 | " -> %08X:%04X " | ||
1905 | "%-7s %-6d %-10d %-10d\n", | ||
1906 | ntohl(dest->addr.ip), | ||
1907 | ntohs(dest->port), | ||
1908 | ip_vs_fwd_name(atomic_read(&dest->conn_flags)), | ||
1909 | atomic_read(&dest->weight), | ||
1910 | atomic_read(&dest->activeconns), | ||
1911 | atomic_read(&dest->inactconns)); | ||
1912 | |||
1776 | } | 1913 | } |
1777 | } | 1914 | } |
1778 | return 0; | 1915 | return 0; |
@@ -1816,20 +1953,20 @@ static int ip_vs_stats_show(struct seq_file *seq, void *v) | |||
1816 | " Conns Packets Packets Bytes Bytes\n"); | 1953 | " Conns Packets Packets Bytes Bytes\n"); |
1817 | 1954 | ||
1818 | spin_lock_bh(&ip_vs_stats.lock); | 1955 | spin_lock_bh(&ip_vs_stats.lock); |
1819 | seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", ip_vs_stats.conns, | 1956 | seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", ip_vs_stats.ustats.conns, |
1820 | ip_vs_stats.inpkts, ip_vs_stats.outpkts, | 1957 | ip_vs_stats.ustats.inpkts, ip_vs_stats.ustats.outpkts, |
1821 | (unsigned long long) ip_vs_stats.inbytes, | 1958 | (unsigned long long) ip_vs_stats.ustats.inbytes, |
1822 | (unsigned long long) ip_vs_stats.outbytes); | 1959 | (unsigned long long) ip_vs_stats.ustats.outbytes); |
1823 | 1960 | ||
1824 | /* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ | 1961 | /* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ |
1825 | seq_puts(seq, | 1962 | seq_puts(seq, |
1826 | " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n"); | 1963 | " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n"); |
1827 | seq_printf(seq,"%8X %8X %8X %16X %16X\n", | 1964 | seq_printf(seq,"%8X %8X %8X %16X %16X\n", |
1828 | ip_vs_stats.cps, | 1965 | ip_vs_stats.ustats.cps, |
1829 | ip_vs_stats.inpps, | 1966 | ip_vs_stats.ustats.inpps, |
1830 | ip_vs_stats.outpps, | 1967 | ip_vs_stats.ustats.outpps, |
1831 | ip_vs_stats.inbps, | 1968 | ip_vs_stats.ustats.inbps, |
1832 | ip_vs_stats.outbps); | 1969 | ip_vs_stats.ustats.outbps); |
1833 | spin_unlock_bh(&ip_vs_stats.lock); | 1970 | spin_unlock_bh(&ip_vs_stats.lock); |
1834 | 1971 | ||
1835 | return 0; | 1972 | return 0; |
@@ -1904,14 +2041,44 @@ static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = { | |||
1904 | [SET_CMDID(IP_VS_SO_SET_ZERO)] = SERVICE_ARG_LEN, | 2041 | [SET_CMDID(IP_VS_SO_SET_ZERO)] = SERVICE_ARG_LEN, |
1905 | }; | 2042 | }; |
1906 | 2043 | ||
2044 | static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc, | ||
2045 | struct ip_vs_service_user *usvc_compat) | ||
2046 | { | ||
2047 | usvc->af = AF_INET; | ||
2048 | usvc->protocol = usvc_compat->protocol; | ||
2049 | usvc->addr.ip = usvc_compat->addr; | ||
2050 | usvc->port = usvc_compat->port; | ||
2051 | usvc->fwmark = usvc_compat->fwmark; | ||
2052 | |||
2053 | /* Deep copy of sched_name is not needed here */ | ||
2054 | usvc->sched_name = usvc_compat->sched_name; | ||
2055 | |||
2056 | usvc->flags = usvc_compat->flags; | ||
2057 | usvc->timeout = usvc_compat->timeout; | ||
2058 | usvc->netmask = usvc_compat->netmask; | ||
2059 | } | ||
2060 | |||
2061 | static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest, | ||
2062 | struct ip_vs_dest_user *udest_compat) | ||
2063 | { | ||
2064 | udest->addr.ip = udest_compat->addr; | ||
2065 | udest->port = udest_compat->port; | ||
2066 | udest->conn_flags = udest_compat->conn_flags; | ||
2067 | udest->weight = udest_compat->weight; | ||
2068 | udest->u_threshold = udest_compat->u_threshold; | ||
2069 | udest->l_threshold = udest_compat->l_threshold; | ||
2070 | } | ||
2071 | |||
1907 | static int | 2072 | static int |
1908 | do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) | 2073 | do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) |
1909 | { | 2074 | { |
1910 | int ret; | 2075 | int ret; |
1911 | unsigned char arg[MAX_ARG_LEN]; | 2076 | unsigned char arg[MAX_ARG_LEN]; |
1912 | struct ip_vs_service_user *usvc; | 2077 | struct ip_vs_service_user *usvc_compat; |
2078 | struct ip_vs_service_user_kern usvc; | ||
1913 | struct ip_vs_service *svc; | 2079 | struct ip_vs_service *svc; |
1914 | struct ip_vs_dest_user *udest; | 2080 | struct ip_vs_dest_user *udest_compat; |
2081 | struct ip_vs_dest_user_kern udest; | ||
1915 | 2082 | ||
1916 | if (!capable(CAP_NET_ADMIN)) | 2083 | if (!capable(CAP_NET_ADMIN)) |
1917 | return -EPERM; | 2084 | return -EPERM; |
@@ -1951,35 +2118,40 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) | |||
1951 | goto out_unlock; | 2118 | goto out_unlock; |
1952 | } | 2119 | } |
1953 | 2120 | ||
1954 | usvc = (struct ip_vs_service_user *)arg; | 2121 | usvc_compat = (struct ip_vs_service_user *)arg; |
1955 | udest = (struct ip_vs_dest_user *)(usvc + 1); | 2122 | udest_compat = (struct ip_vs_dest_user *)(usvc_compat + 1); |
2123 | |||
2124 | /* We only use the new structs internally, so copy userspace compat | ||
2125 | * structs to extended internal versions */ | ||
2126 | ip_vs_copy_usvc_compat(&usvc, usvc_compat); | ||
2127 | ip_vs_copy_udest_compat(&udest, udest_compat); | ||
1956 | 2128 | ||
1957 | if (cmd == IP_VS_SO_SET_ZERO) { | 2129 | if (cmd == IP_VS_SO_SET_ZERO) { |
1958 | /* if no service address is set, zero counters in all */ | 2130 | /* if no service address is set, zero counters in all */ |
1959 | if (!usvc->fwmark && !usvc->addr && !usvc->port) { | 2131 | if (!usvc.fwmark && !usvc.addr.ip && !usvc.port) { |
1960 | ret = ip_vs_zero_all(); | 2132 | ret = ip_vs_zero_all(); |
1961 | goto out_unlock; | 2133 | goto out_unlock; |
1962 | } | 2134 | } |
1963 | } | 2135 | } |
1964 | 2136 | ||
1965 | /* Check for valid protocol: TCP or UDP, even for fwmark!=0 */ | 2137 | /* Check for valid protocol: TCP or UDP, even for fwmark!=0 */ |
1966 | if (usvc->protocol!=IPPROTO_TCP && usvc->protocol!=IPPROTO_UDP) { | 2138 | if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP) { |
1967 | IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n", | 2139 | IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n", |
1968 | usvc->protocol, NIPQUAD(usvc->addr), | 2140 | usvc.protocol, NIPQUAD(usvc.addr.ip), |
1969 | ntohs(usvc->port), usvc->sched_name); | 2141 | ntohs(usvc.port), usvc.sched_name); |
1970 | ret = -EFAULT; | 2142 | ret = -EFAULT; |
1971 | goto out_unlock; | 2143 | goto out_unlock; |
1972 | } | 2144 | } |
1973 | 2145 | ||
1974 | /* Lookup the exact service by <protocol, addr, port> or fwmark */ | 2146 | /* Lookup the exact service by <protocol, addr, port> or fwmark */ |
1975 | if (usvc->fwmark == 0) | 2147 | if (usvc.fwmark == 0) |
1976 | svc = __ip_vs_service_get(usvc->protocol, | 2148 | svc = __ip_vs_service_get(usvc.af, usvc.protocol, |
1977 | usvc->addr, usvc->port); | 2149 | &usvc.addr, usvc.port); |
1978 | else | 2150 | else |
1979 | svc = __ip_vs_svc_fwm_get(usvc->fwmark); | 2151 | svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark); |
1980 | 2152 | ||
1981 | if (cmd != IP_VS_SO_SET_ADD | 2153 | if (cmd != IP_VS_SO_SET_ADD |
1982 | && (svc == NULL || svc->protocol != usvc->protocol)) { | 2154 | && (svc == NULL || svc->protocol != usvc.protocol)) { |
1983 | ret = -ESRCH; | 2155 | ret = -ESRCH; |
1984 | goto out_unlock; | 2156 | goto out_unlock; |
1985 | } | 2157 | } |
@@ -1989,10 +2161,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) | |||
1989 | if (svc != NULL) | 2161 | if (svc != NULL) |
1990 | ret = -EEXIST; | 2162 | ret = -EEXIST; |
1991 | else | 2163 | else |
1992 | ret = ip_vs_add_service(usvc, &svc); | 2164 | ret = ip_vs_add_service(&usvc, &svc); |
1993 | break; | 2165 | break; |
1994 | case IP_VS_SO_SET_EDIT: | 2166 | case IP_VS_SO_SET_EDIT: |
1995 | ret = ip_vs_edit_service(svc, usvc); | 2167 | ret = ip_vs_edit_service(svc, &usvc); |
1996 | break; | 2168 | break; |
1997 | case IP_VS_SO_SET_DEL: | 2169 | case IP_VS_SO_SET_DEL: |
1998 | ret = ip_vs_del_service(svc); | 2170 | ret = ip_vs_del_service(svc); |
@@ -2003,13 +2175,13 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) | |||
2003 | ret = ip_vs_zero_service(svc); | 2175 | ret = ip_vs_zero_service(svc); |
2004 | break; | 2176 | break; |
2005 | case IP_VS_SO_SET_ADDDEST: | 2177 | case IP_VS_SO_SET_ADDDEST: |
2006 | ret = ip_vs_add_dest(svc, udest); | 2178 | ret = ip_vs_add_dest(svc, &udest); |
2007 | break; | 2179 | break; |
2008 | case IP_VS_SO_SET_EDITDEST: | 2180 | case IP_VS_SO_SET_EDITDEST: |
2009 | ret = ip_vs_edit_dest(svc, udest); | 2181 | ret = ip_vs_edit_dest(svc, &udest); |
2010 | break; | 2182 | break; |
2011 | case IP_VS_SO_SET_DELDEST: | 2183 | case IP_VS_SO_SET_DELDEST: |
2012 | ret = ip_vs_del_dest(svc, udest); | 2184 | ret = ip_vs_del_dest(svc, &udest); |
2013 | break; | 2185 | break; |
2014 | default: | 2186 | default: |
2015 | ret = -EINVAL; | 2187 | ret = -EINVAL; |
@@ -2032,7 +2204,7 @@ static void | |||
2032 | ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src) | 2204 | ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src) |
2033 | { | 2205 | { |
2034 | spin_lock_bh(&src->lock); | 2206 | spin_lock_bh(&src->lock); |
2035 | memcpy(dst, src, (char*)&src->lock - (char*)src); | 2207 | memcpy(dst, &src->ustats, sizeof(*dst)); |
2036 | spin_unlock_bh(&src->lock); | 2208 | spin_unlock_bh(&src->lock); |
2037 | } | 2209 | } |
2038 | 2210 | ||
@@ -2040,7 +2212,7 @@ static void | |||
2040 | ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src) | 2212 | ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src) |
2041 | { | 2213 | { |
2042 | dst->protocol = src->protocol; | 2214 | dst->protocol = src->protocol; |
2043 | dst->addr = src->addr; | 2215 | dst->addr = src->addr.ip; |
2044 | dst->port = src->port; | 2216 | dst->port = src->port; |
2045 | dst->fwmark = src->fwmark; | 2217 | dst->fwmark = src->fwmark; |
2046 | strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name)); | 2218 | strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name)); |
@@ -2062,6 +2234,10 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get, | |||
2062 | 2234 | ||
2063 | for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { | 2235 | for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { |
2064 | list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) { | 2236 | list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) { |
2237 | /* Only expose IPv4 entries to old interface */ | ||
2238 | if (svc->af != AF_INET) | ||
2239 | continue; | ||
2240 | |||
2065 | if (count >= get->num_services) | 2241 | if (count >= get->num_services) |
2066 | goto out; | 2242 | goto out; |
2067 | memset(&entry, 0, sizeof(entry)); | 2243 | memset(&entry, 0, sizeof(entry)); |
@@ -2077,6 +2253,10 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get, | |||
2077 | 2253 | ||
2078 | for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { | 2254 | for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { |
2079 | list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) { | 2255 | list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) { |
2256 | /* Only expose IPv4 entries to old interface */ | ||
2257 | if (svc->af != AF_INET) | ||
2258 | continue; | ||
2259 | |||
2080 | if (count >= get->num_services) | 2260 | if (count >= get->num_services) |
2081 | goto out; | 2261 | goto out; |
2082 | memset(&entry, 0, sizeof(entry)); | 2262 | memset(&entry, 0, sizeof(entry)); |
@@ -2098,13 +2278,15 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get, | |||
2098 | struct ip_vs_get_dests __user *uptr) | 2278 | struct ip_vs_get_dests __user *uptr) |
2099 | { | 2279 | { |
2100 | struct ip_vs_service *svc; | 2280 | struct ip_vs_service *svc; |
2281 | union nf_inet_addr addr = { .ip = get->addr }; | ||
2101 | int ret = 0; | 2282 | int ret = 0; |
2102 | 2283 | ||
2103 | if (get->fwmark) | 2284 | if (get->fwmark) |
2104 | svc = __ip_vs_svc_fwm_get(get->fwmark); | 2285 | svc = __ip_vs_svc_fwm_get(AF_INET, get->fwmark); |
2105 | else | 2286 | else |
2106 | svc = __ip_vs_service_get(get->protocol, | 2287 | svc = __ip_vs_service_get(AF_INET, get->protocol, &addr, |
2107 | get->addr, get->port); | 2288 | get->port); |
2289 | |||
2108 | if (svc) { | 2290 | if (svc) { |
2109 | int count = 0; | 2291 | int count = 0; |
2110 | struct ip_vs_dest *dest; | 2292 | struct ip_vs_dest *dest; |
@@ -2114,7 +2296,7 @@ __ip_vs_get_dest_entries(const struct ip_vs_get_dests *get, | |||
2114 | if (count >= get->num_dests) | 2296 | if (count >= get->num_dests) |
2115 | break; | 2297 | break; |
2116 | 2298 | ||
2117 | entry.addr = dest->addr; | 2299 | entry.addr = dest->addr.ip; |
2118 | entry.port = dest->port; | 2300 | entry.port = dest->port; |
2119 | entry.conn_flags = atomic_read(&dest->conn_flags); | 2301 | entry.conn_flags = atomic_read(&dest->conn_flags); |
2120 | entry.weight = atomic_read(&dest->weight); | 2302 | entry.weight = atomic_read(&dest->weight); |
@@ -2239,13 +2421,15 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
2239 | { | 2421 | { |
2240 | struct ip_vs_service_entry *entry; | 2422 | struct ip_vs_service_entry *entry; |
2241 | struct ip_vs_service *svc; | 2423 | struct ip_vs_service *svc; |
2424 | union nf_inet_addr addr; | ||
2242 | 2425 | ||
2243 | entry = (struct ip_vs_service_entry *)arg; | 2426 | entry = (struct ip_vs_service_entry *)arg; |
2427 | addr.ip = entry->addr; | ||
2244 | if (entry->fwmark) | 2428 | if (entry->fwmark) |
2245 | svc = __ip_vs_svc_fwm_get(entry->fwmark); | 2429 | svc = __ip_vs_svc_fwm_get(AF_INET, entry->fwmark); |
2246 | else | 2430 | else |
2247 | svc = __ip_vs_service_get(entry->protocol, | 2431 | svc = __ip_vs_service_get(AF_INET, entry->protocol, |
2248 | entry->addr, entry->port); | 2432 | &addr, entry->port); |
2249 | if (svc) { | 2433 | if (svc) { |
2250 | ip_vs_copy_service(entry, svc); | 2434 | ip_vs_copy_service(entry, svc); |
2251 | if (copy_to_user(user, entry, sizeof(*entry)) != 0) | 2435 | if (copy_to_user(user, entry, sizeof(*entry)) != 0) |
@@ -2396,16 +2580,16 @@ static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type, | |||
2396 | 2580 | ||
2397 | spin_lock_bh(&stats->lock); | 2581 | spin_lock_bh(&stats->lock); |
2398 | 2582 | ||
2399 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->conns); | 2583 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->ustats.conns); |
2400 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->inpkts); | 2584 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->ustats.inpkts); |
2401 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->outpkts); | 2585 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->ustats.outpkts); |
2402 | NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->inbytes); | 2586 | NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->ustats.inbytes); |
2403 | NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->outbytes); | 2587 | NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->ustats.outbytes); |
2404 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->cps); | 2588 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->ustats.cps); |
2405 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->inpps); | 2589 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->ustats.inpps); |
2406 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->outpps); | 2590 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->ustats.outpps); |
2407 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->inbps); | 2591 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->ustats.inbps); |
2408 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->outbps); | 2592 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->ustats.outbps); |
2409 | 2593 | ||
2410 | spin_unlock_bh(&stats->lock); | 2594 | spin_unlock_bh(&stats->lock); |
2411 | 2595 | ||
@@ -2430,7 +2614,7 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb, | |||
2430 | if (!nl_service) | 2614 | if (!nl_service) |
2431 | return -EMSGSIZE; | 2615 | return -EMSGSIZE; |
2432 | 2616 | ||
2433 | NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, AF_INET); | 2617 | NLA_PUT_U16(skb, IPVS_SVC_ATTR_AF, svc->af); |
2434 | 2618 | ||
2435 | if (svc->fwmark) { | 2619 | if (svc->fwmark) { |
2436 | NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark); | 2620 | NLA_PUT_U32(skb, IPVS_SVC_ATTR_FWMARK, svc->fwmark); |
@@ -2516,7 +2700,7 @@ nla_put_failure: | |||
2516 | return skb->len; | 2700 | return skb->len; |
2517 | } | 2701 | } |
2518 | 2702 | ||
2519 | static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc, | 2703 | static int ip_vs_genl_parse_service(struct ip_vs_service_user_kern *usvc, |
2520 | struct nlattr *nla, int full_entry) | 2704 | struct nlattr *nla, int full_entry) |
2521 | { | 2705 | { |
2522 | struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1]; | 2706 | struct nlattr *attrs[IPVS_SVC_ATTR_MAX + 1]; |
@@ -2536,8 +2720,12 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc, | |||
2536 | if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr)))) | 2720 | if (!(nla_af && (nla_fwmark || (nla_port && nla_protocol && nla_addr)))) |
2537 | return -EINVAL; | 2721 | return -EINVAL; |
2538 | 2722 | ||
2539 | /* For now, only support IPv4 */ | 2723 | usvc->af = nla_get_u16(nla_af); |
2540 | if (nla_get_u16(nla_af) != AF_INET) | 2724 | #ifdef CONFIG_IP_VS_IPV6 |
2725 | if (usvc->af != AF_INET && usvc->af != AF_INET6) | ||
2726 | #else | ||
2727 | if (usvc->af != AF_INET) | ||
2728 | #endif | ||
2541 | return -EAFNOSUPPORT; | 2729 | return -EAFNOSUPPORT; |
2542 | 2730 | ||
2543 | if (nla_fwmark) { | 2731 | if (nla_fwmark) { |
@@ -2569,10 +2757,10 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc, | |||
2569 | 2757 | ||
2570 | /* prefill flags from service if it already exists */ | 2758 | /* prefill flags from service if it already exists */ |
2571 | if (usvc->fwmark) | 2759 | if (usvc->fwmark) |
2572 | svc = __ip_vs_svc_fwm_get(usvc->fwmark); | 2760 | svc = __ip_vs_svc_fwm_get(usvc->af, usvc->fwmark); |
2573 | else | 2761 | else |
2574 | svc = __ip_vs_service_get(usvc->protocol, usvc->addr, | 2762 | svc = __ip_vs_service_get(usvc->af, usvc->protocol, |
2575 | usvc->port); | 2763 | &usvc->addr, usvc->port); |
2576 | if (svc) { | 2764 | if (svc) { |
2577 | usvc->flags = svc->flags; | 2765 | usvc->flags = svc->flags; |
2578 | ip_vs_service_put(svc); | 2766 | ip_vs_service_put(svc); |
@@ -2582,9 +2770,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc, | |||
2582 | /* set new flags from userland */ | 2770 | /* set new flags from userland */ |
2583 | usvc->flags = (usvc->flags & ~flags.mask) | | 2771 | usvc->flags = (usvc->flags & ~flags.mask) | |
2584 | (flags.flags & flags.mask); | 2772 | (flags.flags & flags.mask); |
2585 | 2773 | usvc->sched_name = nla_data(nla_sched); | |
2586 | strlcpy(usvc->sched_name, nla_data(nla_sched), | ||
2587 | sizeof(usvc->sched_name)); | ||
2588 | usvc->timeout = nla_get_u32(nla_timeout); | 2774 | usvc->timeout = nla_get_u32(nla_timeout); |
2589 | usvc->netmask = nla_get_u32(nla_netmask); | 2775 | usvc->netmask = nla_get_u32(nla_netmask); |
2590 | } | 2776 | } |
@@ -2594,7 +2780,7 @@ static int ip_vs_genl_parse_service(struct ip_vs_service_user *usvc, | |||
2594 | 2780 | ||
2595 | static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla) | 2781 | static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla) |
2596 | { | 2782 | { |
2597 | struct ip_vs_service_user usvc; | 2783 | struct ip_vs_service_user_kern usvc; |
2598 | int ret; | 2784 | int ret; |
2599 | 2785 | ||
2600 | ret = ip_vs_genl_parse_service(&usvc, nla, 0); | 2786 | ret = ip_vs_genl_parse_service(&usvc, nla, 0); |
@@ -2602,10 +2788,10 @@ static struct ip_vs_service *ip_vs_genl_find_service(struct nlattr *nla) | |||
2602 | return ERR_PTR(ret); | 2788 | return ERR_PTR(ret); |
2603 | 2789 | ||
2604 | if (usvc.fwmark) | 2790 | if (usvc.fwmark) |
2605 | return __ip_vs_svc_fwm_get(usvc.fwmark); | 2791 | return __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark); |
2606 | else | 2792 | else |
2607 | return __ip_vs_service_get(usvc.protocol, usvc.addr, | 2793 | return __ip_vs_service_get(usvc.af, usvc.protocol, |
2608 | usvc.port); | 2794 | &usvc.addr, usvc.port); |
2609 | } | 2795 | } |
2610 | 2796 | ||
2611 | static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest) | 2797 | static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest) |
@@ -2704,7 +2890,7 @@ out_err: | |||
2704 | return skb->len; | 2890 | return skb->len; |
2705 | } | 2891 | } |
2706 | 2892 | ||
2707 | static int ip_vs_genl_parse_dest(struct ip_vs_dest_user *udest, | 2893 | static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest, |
2708 | struct nlattr *nla, int full_entry) | 2894 | struct nlattr *nla, int full_entry) |
2709 | { | 2895 | { |
2710 | struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1]; | 2896 | struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1]; |
@@ -2860,8 +3046,8 @@ static int ip_vs_genl_set_config(struct nlattr **attrs) | |||
2860 | static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) | 3046 | static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) |
2861 | { | 3047 | { |
2862 | struct ip_vs_service *svc = NULL; | 3048 | struct ip_vs_service *svc = NULL; |
2863 | struct ip_vs_service_user usvc; | 3049 | struct ip_vs_service_user_kern usvc; |
2864 | struct ip_vs_dest_user udest; | 3050 | struct ip_vs_dest_user_kern udest; |
2865 | int ret = 0, cmd; | 3051 | int ret = 0, cmd; |
2866 | int need_full_svc = 0, need_full_dest = 0; | 3052 | int need_full_svc = 0, need_full_dest = 0; |
2867 | 3053 | ||
@@ -2913,9 +3099,10 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) | |||
2913 | 3099 | ||
2914 | /* Lookup the exact service by <protocol, addr, port> or fwmark */ | 3100 | /* Lookup the exact service by <protocol, addr, port> or fwmark */ |
2915 | if (usvc.fwmark == 0) | 3101 | if (usvc.fwmark == 0) |
2916 | svc = __ip_vs_service_get(usvc.protocol, usvc.addr, usvc.port); | 3102 | svc = __ip_vs_service_get(usvc.af, usvc.protocol, |
3103 | &usvc.addr, usvc.port); | ||
2917 | else | 3104 | else |
2918 | svc = __ip_vs_svc_fwm_get(usvc.fwmark); | 3105 | svc = __ip_vs_svc_fwm_get(usvc.af, usvc.fwmark); |
2919 | 3106 | ||
2920 | /* Unless we're adding a new service, the service must already exist */ | 3107 | /* Unless we're adding a new service, the service must already exist */ |
2921 | if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) { | 3108 | if ((cmd != IPVS_CMD_NEW_SERVICE) && (svc == NULL)) { |