root/net/tipc/monitor.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dom_rec_len
  2. dom_size
  3. map_set
  4. map_get
  5. peer_prev
  6. peer_nxt
  7. peer_head
  8. get_peer
  9. get_self
  10. tipc_mon_is_active
  11. mon_identify_lost_members
  12. mon_apply_domain
  13. mon_update_local_domain
  14. mon_update_neighbors
  15. mon_assign_roles
  16. tipc_mon_remove_peer
  17. tipc_mon_add_peer
  18. tipc_mon_peer_up
  19. tipc_mon_peer_down
  20. tipc_mon_rcv
  21. tipc_mon_prep
  22. tipc_mon_get_state
  23. mon_timeout
  24. tipc_mon_create
  25. tipc_mon_delete
  26. tipc_mon_reinit_self
  27. tipc_nl_monitor_set_threshold
  28. tipc_nl_monitor_get_threshold
  29. __tipc_nl_add_monitor_peer
  30. tipc_nl_add_monitor_peer
  31. __tipc_nl_add_monitor

   1 /*
   2  * net/tipc/monitor.c
   3  *
   4  * Copyright (c) 2016, Ericsson AB
   5  * All rights reserved.
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  * 2. Redistributions in binary form must reproduce the above copyright
  13  *    notice, this list of conditions and the following disclaimer in the
  14  *    documentation and/or other materials provided with the distribution.
  15  * 3. Neither the names of the copyright holders nor the names of its
  16  *    contributors may be used to endorse or promote products derived from
  17  *    this software without specific prior written permission.
  18  *
  19  * Alternatively, this software may be distributed under the terms of the
  20  * GNU General Public License ("GPL") version 2 as published by the Free
  21  * Software Foundation.
  22  *
  23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33  * POSSIBILITY OF SUCH DAMAGE.
  34  */
  35 
  36 #include <net/genetlink.h>
  37 #include "core.h"
  38 #include "addr.h"
  39 #include "monitor.h"
  40 #include "bearer.h"
  41 
  42 #define MAX_MON_DOMAIN       64
  43 #define MON_TIMEOUT          120000
  44 #define MAX_PEER_DOWN_EVENTS 4
  45 
  46 /* struct tipc_mon_domain: domain record to be transferred between peers
  47  * @len: actual size of domain record
  48  * @gen: current generation of sender's domain
  49  * @ack_gen: most recent generation of self's domain acked by peer
  50  * @member_cnt: number of domain member nodes described in this record
  51  * @up_map: bit map indicating which of the members the sender considers up
  52  * @members: identity of the domain members
  53  */
  54 struct tipc_mon_domain {
  55         u16 len;
  56         u16 gen;
  57         u16 ack_gen;
  58         u16 member_cnt;
  59         u64 up_map;
  60         u32 members[MAX_MON_DOMAIN];
  61 };
  62 
  63 /* struct tipc_peer: state of a peer node and its domain
  64  * @addr: tipc node identity of peer
  65  * @head_map: shows which other nodes currently consider peer 'up'
  66  * @domain: most recent domain record from peer
  67  * @hash: position in hashed lookup list
  68  * @list: position in linked list, in circular ascending order by 'addr'
  69  * @applied: number of reported domain members applied on this monitor list
  70  * @is_up: peer is up as seen from this node
  71  * @is_head: peer is assigned domain head as seen from this node
  72  * @is_local: peer is in local domain and should be continuously monitored
  73  * @down_cnt: - numbers of other peers which have reported this on lost
  74  */
  75 struct tipc_peer {
  76         u32 addr;
  77         struct tipc_mon_domain *domain;
  78         struct hlist_node hash;
  79         struct list_head list;
  80         u8 applied;
  81         u8 down_cnt;
  82         bool is_up;
  83         bool is_head;
  84         bool is_local;
  85 };
  86 
  87 struct tipc_monitor {
  88         struct hlist_head peers[NODE_HTABLE_SIZE];
  89         int peer_cnt;
  90         struct tipc_peer *self;
  91         rwlock_t lock;
  92         struct tipc_mon_domain cache;
  93         u16 list_gen;
  94         u16 dom_gen;
  95         struct net *net;
  96         struct timer_list timer;
  97         unsigned long timer_intv;
  98 };
  99 
 100 static struct tipc_monitor *tipc_monitor(struct net *net, int bearer_id)
 101 {
 102         return tipc_net(net)->monitors[bearer_id];
 103 }
 104 
 105 const int tipc_max_domain_size = sizeof(struct tipc_mon_domain);
 106 
 107 /* dom_rec_len(): actual length of domain record for transport
 108  */
 109 static int dom_rec_len(struct tipc_mon_domain *dom, u16 mcnt)
 110 {
 111         return ((void *)&dom->members - (void *)dom) + (mcnt * sizeof(u32));
 112 }
 113 
 114 /* dom_size() : calculate size of own domain based on number of peers
 115  */
 116 static int dom_size(int peers)
 117 {
 118         int i = 0;
 119 
 120         while ((i * i) < peers)
 121                 i++;
 122         return i < MAX_MON_DOMAIN ? i : MAX_MON_DOMAIN;
 123 }
 124 
 125 static void map_set(u64 *up_map, int i, unsigned int v)
 126 {
 127         *up_map &= ~(1ULL << i);
 128         *up_map |= ((u64)v << i);
 129 }
 130 
 131 static int map_get(u64 up_map, int i)
 132 {
 133         return (up_map & (1 << i)) >> i;
 134 }
 135 
 136 static struct tipc_peer *peer_prev(struct tipc_peer *peer)
 137 {
 138         return list_last_entry(&peer->list, struct tipc_peer, list);
 139 }
 140 
 141 static struct tipc_peer *peer_nxt(struct tipc_peer *peer)
 142 {
 143         return list_first_entry(&peer->list, struct tipc_peer, list);
 144 }
 145 
 146 static struct tipc_peer *peer_head(struct tipc_peer *peer)
 147 {
 148         while (!peer->is_head)
 149                 peer = peer_prev(peer);
 150         return peer;
 151 }
 152 
 153 static struct tipc_peer *get_peer(struct tipc_monitor *mon, u32 addr)
 154 {
 155         struct tipc_peer *peer;
 156         unsigned int thash = tipc_hashfn(addr);
 157 
 158         hlist_for_each_entry(peer, &mon->peers[thash], hash) {
 159                 if (peer->addr == addr)
 160                         return peer;
 161         }
 162         return NULL;
 163 }
 164 
 165 static struct tipc_peer *get_self(struct net *net, int bearer_id)
 166 {
 167         struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 168 
 169         return mon->self;
 170 }
 171 
 172 static inline bool tipc_mon_is_active(struct net *net, struct tipc_monitor *mon)
 173 {
 174         struct tipc_net *tn = tipc_net(net);
 175 
 176         return mon->peer_cnt > tn->mon_threshold;
 177 }
 178 
 179 /* mon_identify_lost_members() : - identify amd mark potentially lost members
 180  */
 181 static void mon_identify_lost_members(struct tipc_peer *peer,
 182                                       struct tipc_mon_domain *dom_bef,
 183                                       int applied_bef)
 184 {
 185         struct tipc_peer *member = peer;
 186         struct tipc_mon_domain *dom_aft = peer->domain;
 187         int applied_aft = peer->applied;
 188         int i;
 189 
 190         for (i = 0; i < applied_bef; i++) {
 191                 member = peer_nxt(member);
 192 
 193                 /* Do nothing if self or peer already see member as down */
 194                 if (!member->is_up || !map_get(dom_bef->up_map, i))
 195                         continue;
 196 
 197                 /* Loss of local node must be detected by active probing */
 198                 if (member->is_local)
 199                         continue;
 200 
 201                 /* Start probing if member was removed from applied domain */
 202                 if (!applied_aft || (applied_aft < i)) {
 203                         member->down_cnt = 1;
 204                         continue;
 205                 }
 206 
 207                 /* Member loss is confirmed if it is still in applied domain */
 208                 if (!map_get(dom_aft->up_map, i))
 209                         member->down_cnt++;
 210         }
 211 }
 212 
 213 /* mon_apply_domain() : match a peer's domain record against monitor list
 214  */
 215 static void mon_apply_domain(struct tipc_monitor *mon,
 216                              struct tipc_peer *peer)
 217 {
 218         struct tipc_mon_domain *dom = peer->domain;
 219         struct tipc_peer *member;
 220         u32 addr;
 221         int i;
 222 
 223         if (!dom || !peer->is_up)
 224                 return;
 225 
 226         /* Scan across domain members and match against monitor list */
 227         peer->applied = 0;
 228         member = peer_nxt(peer);
 229         for (i = 0; i < dom->member_cnt; i++) {
 230                 addr = dom->members[i];
 231                 if (addr != member->addr)
 232                         return;
 233                 peer->applied++;
 234                 member = peer_nxt(member);
 235         }
 236 }
 237 
 238 /* mon_update_local_domain() : update after peer addition/removal/up/down
 239  */
 240 static void mon_update_local_domain(struct tipc_monitor *mon)
 241 {
 242         struct tipc_peer *self = mon->self;
 243         struct tipc_mon_domain *cache = &mon->cache;
 244         struct tipc_mon_domain *dom = self->domain;
 245         struct tipc_peer *peer = self;
 246         u64 prev_up_map = dom->up_map;
 247         u16 member_cnt, i;
 248         bool diff;
 249 
 250         /* Update local domain size based on current size of cluster */
 251         member_cnt = dom_size(mon->peer_cnt) - 1;
 252         self->applied = member_cnt;
 253 
 254         /* Update native and cached outgoing local domain records */
 255         dom->len = dom_rec_len(dom, member_cnt);
 256         diff = dom->member_cnt != member_cnt;
 257         dom->member_cnt = member_cnt;
 258         for (i = 0; i < member_cnt; i++) {
 259                 peer = peer_nxt(peer);
 260                 diff |= dom->members[i] != peer->addr;
 261                 dom->members[i] = peer->addr;
 262                 map_set(&dom->up_map, i, peer->is_up);
 263                 cache->members[i] = htonl(peer->addr);
 264         }
 265         diff |= dom->up_map != prev_up_map;
 266         if (!diff)
 267                 return;
 268         dom->gen = ++mon->dom_gen;
 269         cache->len = htons(dom->len);
 270         cache->gen = htons(dom->gen);
 271         cache->member_cnt = htons(member_cnt);
 272         cache->up_map = cpu_to_be64(dom->up_map);
 273         mon_apply_domain(mon, self);
 274 }
 275 
 276 /* mon_update_neighbors() : update preceding neighbors of added/removed peer
 277  */
 278 static void mon_update_neighbors(struct tipc_monitor *mon,
 279                                  struct tipc_peer *peer)
 280 {
 281         int dz, i;
 282 
 283         dz = dom_size(mon->peer_cnt);
 284         for (i = 0; i < dz; i++) {
 285                 mon_apply_domain(mon, peer);
 286                 peer = peer_prev(peer);
 287         }
 288 }
 289 
 290 /* mon_assign_roles() : reassign peer roles after a network change
 291  * The monitor list is consistent at this stage; i.e., each peer is monitoring
 292  * a set of domain members as matched between domain record and the monitor list
 293  */
 294 static void mon_assign_roles(struct tipc_monitor *mon, struct tipc_peer *head)
 295 {
 296         struct tipc_peer *peer = peer_nxt(head);
 297         struct tipc_peer *self = mon->self;
 298         int i = 0;
 299 
 300         for (; peer != self; peer = peer_nxt(peer)) {
 301                 peer->is_local = false;
 302 
 303                 /* Update domain member */
 304                 if (i++ < head->applied) {
 305                         peer->is_head = false;
 306                         if (head == self)
 307                                 peer->is_local = true;
 308                         continue;
 309                 }
 310                 /* Assign next domain head */
 311                 if (!peer->is_up)
 312                         continue;
 313                 if (peer->is_head)
 314                         break;
 315                 head = peer;
 316                 head->is_head = true;
 317                 i = 0;
 318         }
 319         mon->list_gen++;
 320 }
 321 
 322 void tipc_mon_remove_peer(struct net *net, u32 addr, int bearer_id)
 323 {
 324         struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 325         struct tipc_peer *self = get_self(net, bearer_id);
 326         struct tipc_peer *peer, *prev, *head;
 327 
 328         write_lock_bh(&mon->lock);
 329         peer = get_peer(mon, addr);
 330         if (!peer)
 331                 goto exit;
 332         prev = peer_prev(peer);
 333         list_del(&peer->list);
 334         hlist_del(&peer->hash);
 335         kfree(peer->domain);
 336         kfree(peer);
 337         mon->peer_cnt--;
 338         head = peer_head(prev);
 339         if (head == self)
 340                 mon_update_local_domain(mon);
 341         mon_update_neighbors(mon, prev);
 342 
 343         /* Revert to full-mesh monitoring if we reach threshold */
 344         if (!tipc_mon_is_active(net, mon)) {
 345                 list_for_each_entry(peer, &self->list, list) {
 346                         kfree(peer->domain);
 347                         peer->domain = NULL;
 348                         peer->applied = 0;
 349                 }
 350         }
 351         mon_assign_roles(mon, head);
 352 exit:
 353         write_unlock_bh(&mon->lock);
 354 }
 355 
 356 static bool tipc_mon_add_peer(struct tipc_monitor *mon, u32 addr,
 357                               struct tipc_peer **peer)
 358 {
 359         struct tipc_peer *self = mon->self;
 360         struct tipc_peer *cur, *prev, *p;
 361 
 362         p = kzalloc(sizeof(*p), GFP_ATOMIC);
 363         *peer = p;
 364         if (!p)
 365                 return false;
 366         p->addr = addr;
 367 
 368         /* Add new peer to lookup list */
 369         INIT_LIST_HEAD(&p->list);
 370         hlist_add_head(&p->hash, &mon->peers[tipc_hashfn(addr)]);
 371 
 372         /* Sort new peer into iterator list, in ascending circular order */
 373         prev = self;
 374         list_for_each_entry(cur, &self->list, list) {
 375                 if ((addr > prev->addr) && (addr < cur->addr))
 376                         break;
 377                 if (((addr < cur->addr) || (addr > prev->addr)) &&
 378                     (prev->addr > cur->addr))
 379                         break;
 380                 prev = cur;
 381         }
 382         list_add_tail(&p->list, &cur->list);
 383         mon->peer_cnt++;
 384         mon_update_neighbors(mon, p);
 385         return true;
 386 }
 387 
 388 void tipc_mon_peer_up(struct net *net, u32 addr, int bearer_id)
 389 {
 390         struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 391         struct tipc_peer *self = get_self(net, bearer_id);
 392         struct tipc_peer *peer, *head;
 393 
 394         write_lock_bh(&mon->lock);
 395         peer = get_peer(mon, addr);
 396         if (!peer && !tipc_mon_add_peer(mon, addr, &peer))
 397                 goto exit;
 398         peer->is_up = true;
 399         head = peer_head(peer);
 400         if (head == self)
 401                 mon_update_local_domain(mon);
 402         mon_assign_roles(mon, head);
 403 exit:
 404         write_unlock_bh(&mon->lock);
 405 }
 406 
 407 void tipc_mon_peer_down(struct net *net, u32 addr, int bearer_id)
 408 {
 409         struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 410         struct tipc_peer *self = get_self(net, bearer_id);
 411         struct tipc_peer *peer, *head;
 412         struct tipc_mon_domain *dom;
 413         int applied;
 414 
 415         write_lock_bh(&mon->lock);
 416         peer = get_peer(mon, addr);
 417         if (!peer) {
 418                 pr_warn("Mon: unknown link %x/%u DOWN\n", addr, bearer_id);
 419                 goto exit;
 420         }
 421         applied = peer->applied;
 422         peer->applied = 0;
 423         dom = peer->domain;
 424         peer->domain = NULL;
 425         if (peer->is_head)
 426                 mon_identify_lost_members(peer, dom, applied);
 427         kfree(dom);
 428         peer->is_up = false;
 429         peer->is_head = false;
 430         peer->is_local = false;
 431         peer->down_cnt = 0;
 432         head = peer_head(peer);
 433         if (head == self)
 434                 mon_update_local_domain(mon);
 435         mon_assign_roles(mon, head);
 436 exit:
 437         write_unlock_bh(&mon->lock);
 438 }
 439 
 440 /* tipc_mon_rcv - process monitor domain event message
 441  */
 442 void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
 443                   struct tipc_mon_state *state, int bearer_id)
 444 {
 445         struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 446         struct tipc_mon_domain *arrv_dom = data;
 447         struct tipc_mon_domain dom_bef;
 448         struct tipc_mon_domain *dom;
 449         struct tipc_peer *peer;
 450         u16 new_member_cnt = ntohs(arrv_dom->member_cnt);
 451         int new_dlen = dom_rec_len(arrv_dom, new_member_cnt);
 452         u16 new_gen = ntohs(arrv_dom->gen);
 453         u16 acked_gen = ntohs(arrv_dom->ack_gen);
 454         bool probing = state->probing;
 455         int i, applied_bef;
 456 
 457         state->probing = false;
 458 
 459         /* Sanity check received domain record */
 460         if (dlen < dom_rec_len(arrv_dom, 0))
 461                 return;
 462         if (dlen != dom_rec_len(arrv_dom, new_member_cnt))
 463                 return;
 464         if ((dlen < new_dlen) || ntohs(arrv_dom->len) != new_dlen)
 465                 return;
 466 
 467         /* Synch generation numbers with peer if link just came up */
 468         if (!state->synched) {
 469                 state->peer_gen = new_gen - 1;
 470                 state->acked_gen = acked_gen;
 471                 state->synched = true;
 472         }
 473 
 474         if (more(acked_gen, state->acked_gen))
 475                 state->acked_gen = acked_gen;
 476 
 477         /* Drop duplicate unless we are waiting for a probe response */
 478         if (!more(new_gen, state->peer_gen) && !probing)
 479                 return;
 480 
 481         write_lock_bh(&mon->lock);
 482         peer = get_peer(mon, addr);
 483         if (!peer || !peer->is_up)
 484                 goto exit;
 485 
 486         /* Peer is confirmed, stop any ongoing probing */
 487         peer->down_cnt = 0;
 488 
 489         /* Task is done for duplicate record */
 490         if (!more(new_gen, state->peer_gen))
 491                 goto exit;
 492 
 493         state->peer_gen = new_gen;
 494 
 495         /* Cache current domain record for later use */
 496         dom_bef.member_cnt = 0;
 497         dom = peer->domain;
 498         if (dom)
 499                 memcpy(&dom_bef, dom, dom->len);
 500 
 501         /* Transform and store received domain record */
 502         if (!dom || (dom->len < new_dlen)) {
 503                 kfree(dom);
 504                 dom = kmalloc(new_dlen, GFP_ATOMIC);
 505                 peer->domain = dom;
 506                 if (!dom)
 507                         goto exit;
 508         }
 509         dom->len = new_dlen;
 510         dom->gen = new_gen;
 511         dom->member_cnt = new_member_cnt;
 512         dom->up_map = be64_to_cpu(arrv_dom->up_map);
 513         for (i = 0; i < new_member_cnt; i++)
 514                 dom->members[i] = ntohl(arrv_dom->members[i]);
 515 
 516         /* Update peers affected by this domain record */
 517         applied_bef = peer->applied;
 518         mon_apply_domain(mon, peer);
 519         mon_identify_lost_members(peer, &dom_bef, applied_bef);
 520         mon_assign_roles(mon, peer_head(peer));
 521 exit:
 522         write_unlock_bh(&mon->lock);
 523 }
 524 
 525 void tipc_mon_prep(struct net *net, void *data, int *dlen,
 526                    struct tipc_mon_state *state, int bearer_id)
 527 {
 528         struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 529         struct tipc_mon_domain *dom = data;
 530         u16 gen = mon->dom_gen;
 531         u16 len;
 532 
 533         /* Send invalid record if not active */
 534         if (!tipc_mon_is_active(net, mon)) {
 535                 dom->len = 0;
 536                 return;
 537         }
 538 
 539         /* Send only a dummy record with ack if peer has acked our last sent */
 540         if (likely(state->acked_gen == gen)) {
 541                 len = dom_rec_len(dom, 0);
 542                 *dlen = len;
 543                 dom->len = htons(len);
 544                 dom->gen = htons(gen);
 545                 dom->ack_gen = htons(state->peer_gen);
 546                 dom->member_cnt = 0;
 547                 return;
 548         }
 549         /* Send the full record */
 550         read_lock_bh(&mon->lock);
 551         len = ntohs(mon->cache.len);
 552         *dlen = len;
 553         memcpy(data, &mon->cache, len);
 554         read_unlock_bh(&mon->lock);
 555         dom->ack_gen = htons(state->peer_gen);
 556 }
 557 
 558 void tipc_mon_get_state(struct net *net, u32 addr,
 559                         struct tipc_mon_state *state,
 560                         int bearer_id)
 561 {
 562         struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 563         struct tipc_peer *peer;
 564 
 565         if (!tipc_mon_is_active(net, mon)) {
 566                 state->probing = false;
 567                 state->monitoring = true;
 568                 return;
 569         }
 570 
 571         /* Used cached state if table has not changed */
 572         if (!state->probing &&
 573             (state->list_gen == mon->list_gen) &&
 574             (state->acked_gen == mon->dom_gen))
 575                 return;
 576 
 577         read_lock_bh(&mon->lock);
 578         peer = get_peer(mon, addr);
 579         if (peer) {
 580                 state->probing = state->acked_gen != mon->dom_gen;
 581                 state->probing |= peer->down_cnt;
 582                 state->reset |= peer->down_cnt >= MAX_PEER_DOWN_EVENTS;
 583                 state->monitoring = peer->is_local;
 584                 state->monitoring |= peer->is_head;
 585                 state->list_gen = mon->list_gen;
 586         }
 587         read_unlock_bh(&mon->lock);
 588 }
 589 
 590 static void mon_timeout(struct timer_list *t)
 591 {
 592         struct tipc_monitor *mon = from_timer(mon, t, timer);
 593         struct tipc_peer *self;
 594         int best_member_cnt = dom_size(mon->peer_cnt) - 1;
 595 
 596         write_lock_bh(&mon->lock);
 597         self = mon->self;
 598         if (self && (best_member_cnt != self->applied)) {
 599                 mon_update_local_domain(mon);
 600                 mon_assign_roles(mon, self);
 601         }
 602         write_unlock_bh(&mon->lock);
 603         mod_timer(&mon->timer, jiffies + mon->timer_intv);
 604 }
 605 
 606 int tipc_mon_create(struct net *net, int bearer_id)
 607 {
 608         struct tipc_net *tn = tipc_net(net);
 609         struct tipc_monitor *mon;
 610         struct tipc_peer *self;
 611         struct tipc_mon_domain *dom;
 612 
 613         if (tn->monitors[bearer_id])
 614                 return 0;
 615 
 616         mon = kzalloc(sizeof(*mon), GFP_ATOMIC);
 617         self = kzalloc(sizeof(*self), GFP_ATOMIC);
 618         dom = kzalloc(sizeof(*dom), GFP_ATOMIC);
 619         if (!mon || !self || !dom) {
 620                 kfree(mon);
 621                 kfree(self);
 622                 kfree(dom);
 623                 return -ENOMEM;
 624         }
 625         tn->monitors[bearer_id] = mon;
 626         rwlock_init(&mon->lock);
 627         mon->net = net;
 628         mon->peer_cnt = 1;
 629         mon->self = self;
 630         self->domain = dom;
 631         self->addr = tipc_own_addr(net);
 632         self->is_up = true;
 633         self->is_head = true;
 634         INIT_LIST_HEAD(&self->list);
 635         timer_setup(&mon->timer, mon_timeout, 0);
 636         mon->timer_intv = msecs_to_jiffies(MON_TIMEOUT + (tn->random & 0xffff));
 637         mod_timer(&mon->timer, jiffies + mon->timer_intv);
 638         return 0;
 639 }
 640 
 641 void tipc_mon_delete(struct net *net, int bearer_id)
 642 {
 643         struct tipc_net *tn = tipc_net(net);
 644         struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 645         struct tipc_peer *self;
 646         struct tipc_peer *peer, *tmp;
 647 
 648         if (!mon)
 649                 return;
 650 
 651         self = get_self(net, bearer_id);
 652         write_lock_bh(&mon->lock);
 653         tn->monitors[bearer_id] = NULL;
 654         list_for_each_entry_safe(peer, tmp, &self->list, list) {
 655                 list_del(&peer->list);
 656                 hlist_del(&peer->hash);
 657                 kfree(peer->domain);
 658                 kfree(peer);
 659         }
 660         mon->self = NULL;
 661         write_unlock_bh(&mon->lock);
 662         del_timer_sync(&mon->timer);
 663         kfree(self->domain);
 664         kfree(self);
 665         kfree(mon);
 666 }
 667 
 668 void tipc_mon_reinit_self(struct net *net)
 669 {
 670         struct tipc_monitor *mon;
 671         int bearer_id;
 672 
 673         for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {
 674                 mon = tipc_monitor(net, bearer_id);
 675                 if (!mon)
 676                         continue;
 677                 write_lock_bh(&mon->lock);
 678                 mon->self->addr = tipc_own_addr(net);
 679                 write_unlock_bh(&mon->lock);
 680         }
 681 }
 682 
 683 int tipc_nl_monitor_set_threshold(struct net *net, u32 cluster_size)
 684 {
 685         struct tipc_net *tn = tipc_net(net);
 686 
 687         if (cluster_size > TIPC_CLUSTER_SIZE)
 688                 return -EINVAL;
 689 
 690         tn->mon_threshold = cluster_size;
 691 
 692         return 0;
 693 }
 694 
 695 int tipc_nl_monitor_get_threshold(struct net *net)
 696 {
 697         struct tipc_net *tn = tipc_net(net);
 698 
 699         return tn->mon_threshold;
 700 }
 701 
 702 static int __tipc_nl_add_monitor_peer(struct tipc_peer *peer,
 703                                       struct tipc_nl_msg *msg)
 704 {
 705         struct tipc_mon_domain *dom = peer->domain;
 706         struct nlattr *attrs;
 707         void *hdr;
 708 
 709         hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
 710                           NLM_F_MULTI, TIPC_NL_MON_PEER_GET);
 711         if (!hdr)
 712                 return -EMSGSIZE;
 713 
 714         attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_MON_PEER);
 715         if (!attrs)
 716                 goto msg_full;
 717 
 718         if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_ADDR, peer->addr))
 719                 goto attr_msg_full;
 720         if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_APPLIED, peer->applied))
 721                 goto attr_msg_full;
 722 
 723         if (peer->is_up)
 724                 if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_UP))
 725                         goto attr_msg_full;
 726         if (peer->is_local)
 727                 if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_LOCAL))
 728                         goto attr_msg_full;
 729         if (peer->is_head)
 730                 if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_HEAD))
 731                         goto attr_msg_full;
 732 
 733         if (dom) {
 734                 if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_DOMGEN, dom->gen))
 735                         goto attr_msg_full;
 736                 if (nla_put_u64_64bit(msg->skb, TIPC_NLA_MON_PEER_UPMAP,
 737                                       dom->up_map, TIPC_NLA_MON_PEER_PAD))
 738                         goto attr_msg_full;
 739                 if (nla_put(msg->skb, TIPC_NLA_MON_PEER_MEMBERS,
 740                             dom->member_cnt * sizeof(u32), &dom->members))
 741                         goto attr_msg_full;
 742         }
 743 
 744         nla_nest_end(msg->skb, attrs);
 745         genlmsg_end(msg->skb, hdr);
 746         return 0;
 747 
 748 attr_msg_full:
 749         nla_nest_cancel(msg->skb, attrs);
 750 msg_full:
 751         genlmsg_cancel(msg->skb, hdr);
 752 
 753         return -EMSGSIZE;
 754 }
 755 
 756 int tipc_nl_add_monitor_peer(struct net *net, struct tipc_nl_msg *msg,
 757                              u32 bearer_id, u32 *prev_node)
 758 {
 759         struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 760         struct tipc_peer *peer;
 761 
 762         if (!mon)
 763                 return -EINVAL;
 764 
 765         read_lock_bh(&mon->lock);
 766         peer = mon->self;
 767         do {
 768                 if (*prev_node) {
 769                         if (peer->addr == *prev_node)
 770                                 *prev_node = 0;
 771                         else
 772                                 continue;
 773                 }
 774                 if (__tipc_nl_add_monitor_peer(peer, msg)) {
 775                         *prev_node = peer->addr;
 776                         read_unlock_bh(&mon->lock);
 777                         return -EMSGSIZE;
 778                 }
 779         } while ((peer = peer_nxt(peer)) != mon->self);
 780         read_unlock_bh(&mon->lock);
 781 
 782         return 0;
 783 }
 784 
 785 int __tipc_nl_add_monitor(struct net *net, struct tipc_nl_msg *msg,
 786                           u32 bearer_id)
 787 {
 788         struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
 789         char bearer_name[TIPC_MAX_BEARER_NAME];
 790         struct nlattr *attrs;
 791         void *hdr;
 792         int ret;
 793 
 794         ret = tipc_bearer_get_name(net, bearer_name, bearer_id);
 795         if (ret || !mon)
 796                 return 0;
 797 
 798         hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
 799                           NLM_F_MULTI, TIPC_NL_MON_GET);
 800         if (!hdr)
 801                 return -EMSGSIZE;
 802 
 803         attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_MON);
 804         if (!attrs)
 805                 goto msg_full;
 806 
 807         read_lock_bh(&mon->lock);
 808         if (nla_put_u32(msg->skb, TIPC_NLA_MON_REF, bearer_id))
 809                 goto attr_msg_full;
 810         if (tipc_mon_is_active(net, mon))
 811                 if (nla_put_flag(msg->skb, TIPC_NLA_MON_ACTIVE))
 812                         goto attr_msg_full;
 813         if (nla_put_string(msg->skb, TIPC_NLA_MON_BEARER_NAME, bearer_name))
 814                 goto attr_msg_full;
 815         if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEERCNT, mon->peer_cnt))
 816                 goto attr_msg_full;
 817         if (nla_put_u32(msg->skb, TIPC_NLA_MON_LISTGEN, mon->list_gen))
 818                 goto attr_msg_full;
 819 
 820         read_unlock_bh(&mon->lock);
 821         nla_nest_end(msg->skb, attrs);
 822         genlmsg_end(msg->skb, hdr);
 823 
 824         return 0;
 825 
 826 attr_msg_full:
 827         read_unlock_bh(&mon->lock);
 828         nla_nest_cancel(msg->skb, attrs);
 829 msg_full:
 830         genlmsg_cancel(msg->skb, hdr);
 831 
 832         return -EMSGSIZE;
 833 }

/* [<][>][^][v][top][bottom][index][help] */