diff options
| -rw-r--r-- | net/tipc/group.c | 7 | ||||
| -rw-r--r-- | net/tipc/group.h | 3 | ||||
| -rw-r--r-- | net/tipc/name_table.c | 41 | ||||
| -rw-r--r-- | net/tipc/name_table.h | 3 | ||||
| -rw-r--r-- | net/tipc/socket.c | 84 |
5 files changed, 138 insertions, 0 deletions
diff --git a/net/tipc/group.c b/net/tipc/group.c index 18440be5b5fc..16aaaa97a005 100644 --- a/net/tipc/group.c +++ b/net/tipc/group.c | |||
| @@ -116,6 +116,13 @@ static bool tipc_group_is_receiver(struct tipc_member *m) | |||
| 116 | return m && m->state >= MBR_JOINED; | 116 | return m && m->state >= MBR_JOINED; |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | u32 tipc_group_exclude(struct tipc_group *grp) | ||
| 120 | { | ||
| 121 | if (!grp->loopback) | ||
| 122 | return grp->portid; | ||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 119 | int tipc_group_size(struct tipc_group *grp) | 126 | int tipc_group_size(struct tipc_group *grp) |
| 120 | { | 127 | { |
| 121 | return grp->member_cnt; | 128 | return grp->member_cnt; |
diff --git a/net/tipc/group.h b/net/tipc/group.h index 8f77290bb415..e432066a211e 100644 --- a/net/tipc/group.h +++ b/net/tipc/group.h | |||
| @@ -49,6 +49,7 @@ void tipc_group_add_member(struct tipc_group *grp, u32 node, u32 port); | |||
| 49 | struct tipc_nlist *tipc_group_dests(struct tipc_group *grp); | 49 | struct tipc_nlist *tipc_group_dests(struct tipc_group *grp); |
| 50 | void tipc_group_self(struct tipc_group *grp, struct tipc_name_seq *seq, | 50 | void tipc_group_self(struct tipc_group *grp, struct tipc_name_seq *seq, |
| 51 | int *scope); | 51 | int *scope); |
| 52 | u32 tipc_group_exclude(struct tipc_group *grp); | ||
| 52 | void tipc_group_filter_msg(struct tipc_group *grp, | 53 | void tipc_group_filter_msg(struct tipc_group *grp, |
| 53 | struct sk_buff_head *inputq, | 54 | struct sk_buff_head *inputq, |
| 54 | struct sk_buff_head *xmitq); | 55 | struct sk_buff_head *xmitq); |
| @@ -68,5 +69,7 @@ void tipc_group_update_rcv_win(struct tipc_group *grp, int blks, u32 node, | |||
| 68 | u32 port, struct sk_buff_head *xmitq); | 69 | u32 port, struct sk_buff_head *xmitq); |
| 69 | u16 tipc_group_bc_snd_nxt(struct tipc_group *grp); | 70 | u16 tipc_group_bc_snd_nxt(struct tipc_group *grp); |
| 70 | void tipc_group_update_member(struct tipc_member *m, int len); | 71 | void tipc_group_update_member(struct tipc_member *m, int len); |
| 72 | struct tipc_member *tipc_group_find_sender(struct tipc_group *grp, | ||
| 73 | u32 node, u32 port); | ||
| 71 | int tipc_group_size(struct tipc_group *grp); | 74 | int tipc_group_size(struct tipc_group *grp); |
| 72 | #endif | 75 | #endif |
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 114d72bab827..2856e19e036e 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c | |||
| @@ -597,6 +597,47 @@ not_found: | |||
| 597 | return ref; | 597 | return ref; |
| 598 | } | 598 | } |
| 599 | 599 | ||
| 600 | bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 domain, | ||
| 601 | struct list_head *dsts, int *dstcnt, u32 exclude, | ||
| 602 | bool all) | ||
| 603 | { | ||
| 604 | u32 self = tipc_own_addr(net); | ||
| 605 | struct publication *publ; | ||
| 606 | struct name_info *info; | ||
| 607 | struct name_seq *seq; | ||
| 608 | struct sub_seq *sseq; | ||
| 609 | |||
| 610 | if (!tipc_in_scope(domain, self)) | ||
| 611 | return false; | ||
| 612 | |||
| 613 | *dstcnt = 0; | ||
| 614 | rcu_read_lock(); | ||
| 615 | seq = nametbl_find_seq(net, type); | ||
| 616 | if (unlikely(!seq)) | ||
| 617 | goto exit; | ||
| 618 | spin_lock_bh(&seq->lock); | ||
| 619 | sseq = nameseq_find_subseq(seq, instance); | ||
| 620 | if (likely(sseq)) { | ||
| 621 | info = sseq->info; | ||
| 622 | list_for_each_entry(publ, &info->zone_list, zone_list) { | ||
| 623 | if (!tipc_in_scope(domain, publ->node)) | ||
| 624 | continue; | ||
| 625 | if (publ->ref == exclude && publ->node == self) | ||
| 626 | continue; | ||
| 627 | tipc_dest_push(dsts, publ->node, publ->ref); | ||
| 628 | (*dstcnt)++; | ||
| 629 | if (all) | ||
| 630 | continue; | ||
| 631 | list_move_tail(&publ->zone_list, &info->zone_list); | ||
| 632 | break; | ||
| 633 | } | ||
| 634 | } | ||
| 635 | spin_unlock_bh(&seq->lock); | ||
| 636 | exit: | ||
| 637 | rcu_read_unlock(); | ||
| 638 | return !list_empty(dsts); | ||
| 639 | } | ||
| 640 | |||
| 600 | int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper, | 641 | int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper, |
| 601 | u32 limit, struct list_head *dports) | 642 | u32 limit, struct list_head *dports) |
| 602 | { | 643 | { |
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h index 97646b17a4a2..71926e429446 100644 --- a/net/tipc/name_table.h +++ b/net/tipc/name_table.h | |||
| @@ -107,6 +107,9 @@ void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp, | |||
| 107 | void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower, | 107 | void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower, |
| 108 | u32 upper, u32 domain, | 108 | u32 upper, u32 domain, |
| 109 | struct tipc_nlist *nodes); | 109 | struct tipc_nlist *nodes); |
| 110 | bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 domain, | ||
| 111 | struct list_head *dsts, int *dstcnt, u32 exclude, | ||
| 112 | bool all); | ||
| 110 | struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower, | 113 | struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower, |
| 111 | u32 upper, u32 scope, u32 port_ref, | 114 | u32 upper, u32 scope, u32 port_ref, |
| 112 | u32 key); | 115 | u32 key); |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e71c8d23acb9..66165e12d2f4 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
| @@ -905,6 +905,88 @@ static int tipc_send_group_unicast(struct socket *sock, struct msghdr *m, | |||
| 905 | } | 905 | } |
| 906 | 906 | ||
| 907 | /** | 907 | /** |
| 908 | * tipc_send_group_anycast - send message to any member with given identity | ||
| 909 | * @sock: socket structure | ||
| 910 | * @m: message to send | ||
| 911 | * @dlen: total length of message data | ||
| 912 | * @timeout: timeout to wait for wakeup | ||
| 913 | * | ||
| 914 | * Called from function tipc_sendmsg(), which has done all sanity checks | ||
| 915 | * Returns the number of bytes sent on success, or errno | ||
| 916 | */ | ||
| 917 | static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m, | ||
| 918 | int dlen, long timeout) | ||
| 919 | { | ||
| 920 | DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name); | ||
| 921 | struct sock *sk = sock->sk; | ||
| 922 | struct tipc_sock *tsk = tipc_sk(sk); | ||
| 923 | struct list_head *cong_links = &tsk->cong_links; | ||
| 924 | int blks = tsk_blocks(GROUP_H_SIZE + dlen); | ||
| 925 | struct tipc_group *grp = tsk->group; | ||
| 926 | struct tipc_member *first = NULL; | ||
| 927 | struct tipc_member *mbr = NULL; | ||
| 928 | struct net *net = sock_net(sk); | ||
| 929 | u32 node, port, exclude; | ||
| 930 | u32 type, inst, domain; | ||
| 931 | struct list_head dsts; | ||
| 932 | int lookups = 0; | ||
| 933 | int dstcnt, rc; | ||
| 934 | bool cong; | ||
| 935 | |||
| 936 | INIT_LIST_HEAD(&dsts); | ||
| 937 | |||
| 938 | type = dest->addr.name.name.type; | ||
| 939 | inst = dest->addr.name.name.instance; | ||
| 940 | domain = addr_domain(net, dest->scope); | ||
| 941 | exclude = tipc_group_exclude(grp); | ||
| 942 | |||
| 943 | while (++lookups < 4) { | ||
| 944 | first = NULL; | ||
| 945 | |||
| 946 | /* Look for a non-congested destination member, if any */ | ||
| 947 | while (1) { | ||
| 948 | if (!tipc_nametbl_lookup(net, type, inst, domain, &dsts, | ||
| 949 | &dstcnt, exclude, false)) | ||
| 950 | return -EHOSTUNREACH; | ||
| 951 | tipc_dest_pop(&dsts, &node, &port); | ||
| 952 | cong = tipc_group_cong(grp, node, port, blks, &mbr); | ||
| 953 | if (!cong) | ||
| 954 | break; | ||
| 955 | if (mbr == first) | ||
| 956 | break; | ||
| 957 | if (!first) | ||
| 958 | first = mbr; | ||
| 959 | } | ||
| 960 | |||
| 961 | /* Start over if destination was not in member list */ | ||
| 962 | if (unlikely(!mbr)) | ||
| 963 | continue; | ||
| 964 | |||
| 965 | if (likely(!cong && !tipc_dest_find(cong_links, node, 0))) | ||
| 966 | break; | ||
| 967 | |||
| 968 | /* Block or return if destination link or member is congested */ | ||
| 969 | rc = tipc_wait_for_cond(sock, &timeout, | ||
| 970 | !tipc_dest_find(cong_links, node, 0) && | ||
| 971 | !tipc_group_cong(grp, node, port, | ||
| 972 | blks, &mbr)); | ||
| 973 | if (unlikely(rc)) | ||
| 974 | return rc; | ||
| 975 | |||
| 976 | /* Send, unless destination disappeared while waiting */ | ||
| 977 | if (likely(mbr)) | ||
| 978 | break; | ||
| 979 | } | ||
| 980 | |||
| 981 | if (unlikely(lookups >= 4)) | ||
| 982 | return -EHOSTUNREACH; | ||
| 983 | |||
| 984 | rc = tipc_send_group_msg(net, tsk, m, mbr, node, port, dlen); | ||
| 985 | |||
| 986 | return rc ? rc : dlen; | ||
| 987 | } | ||
| 988 | |||
| 989 | /** | ||
| 908 | * tipc_send_group_bcast - send message to all members in communication group | 990 | * tipc_send_group_bcast - send message to all members in communication group |
| 909 | * @sk: socket structure | 991 | * @sk: socket structure |
| 910 | * @m: message to send | 992 | * @m: message to send |
| @@ -1127,6 +1209,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen) | |||
| 1127 | if (grp) { | 1209 | if (grp) { |
| 1128 | if (!dest) | 1210 | if (!dest) |
| 1129 | return tipc_send_group_bcast(sock, m, dlen, timeout); | 1211 | return tipc_send_group_bcast(sock, m, dlen, timeout); |
| 1212 | if (dest->addrtype == TIPC_ADDR_NAME) | ||
| 1213 | return tipc_send_group_anycast(sock, m, dlen, timeout); | ||
| 1130 | if (dest->addrtype == TIPC_ADDR_ID) | 1214 | if (dest->addrtype == TIPC_ADDR_ID) |
| 1131 | return tipc_send_group_unicast(sock, m, dlen, timeout); | 1215 | return tipc_send_group_unicast(sock, m, dlen, timeout); |
| 1132 | return -EINVAL; | 1216 | return -EINVAL; |
