diff options
Diffstat (limited to 'net/tipc')
-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; |