aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2016-08-16 11:53:50 -0400
committerDavid S. Miller <davem@davemloft.net>2016-08-19 00:14:36 -0400
commit0d051bf93c0640483788db56dfc118d307f8893b (patch)
tree360722c2eae3e17cb4801e1dc8f14aeb91437284 /net/tipc
parent37bd91d1d9a9a3ab5e8f7efedadc4ced5d2d0a3a (diff)
tipc: make bearer packet filtering generic
In commit 5b7066c3dd24 ("tipc: stricter filtering of packets in bearer layer") we introduced a method of filtering out messages while a bearer is being reset, to avoid that links may be re-created and come back in working state while we are still in the process of shutting them down. This solution works well, but is limited to only work with L2 media, which is insufficient with the increasing use of UDP as carrier media. We now replace this solution with a more generic one, by introducing a new flag "up" in the generic struct tipc_bearer. This field will be set and reset at the same locations as with the previous solution, while the packet filtering is moved to the generic code for the sending side. On the receiving side, the filtering is still done in media specific code, but now including the UDP bearer. Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/bearer.c78
-rw-r--r--net/tipc/bearer.h1
-rw-r--r--net/tipc/udp_media.c2
3 files changed, 42 insertions, 39 deletions
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 65b1bbf133bd..6fc4e3cca49a 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -56,6 +56,13 @@ static struct tipc_media * const media_info_array[] = {
56 NULL 56 NULL
57}; 57};
58 58
59static struct tipc_bearer *bearer_get(struct net *net, int bearer_id)
60{
61 struct tipc_net *tn = tipc_net(net);
62
63 return rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
64}
65
59static void bearer_disable(struct net *net, struct tipc_bearer *b); 66static void bearer_disable(struct net *net, struct tipc_bearer *b);
60 67
61/** 68/**
@@ -323,6 +330,7 @@ restart:
323 b->domain = disc_domain; 330 b->domain = disc_domain;
324 b->net_plane = bearer_id + 'A'; 331 b->net_plane = bearer_id + 'A';
325 b->priority = priority; 332 b->priority = priority;
333 test_and_set_bit_lock(0, &b->up);
326 334
327 res = tipc_disc_create(net, b, &b->bcast_addr, &skb); 335 res = tipc_disc_create(net, b, &b->bcast_addr, &skb);
328 if (res) { 336 if (res) {
@@ -360,15 +368,24 @@ static int tipc_reset_bearer(struct net *net, struct tipc_bearer *b)
360 */ 368 */
361void tipc_bearer_reset_all(struct net *net) 369void tipc_bearer_reset_all(struct net *net)
362{ 370{
363 struct tipc_net *tn = tipc_net(net);
364 struct tipc_bearer *b; 371 struct tipc_bearer *b;
365 int i; 372 int i;
366 373
367 for (i = 0; i < MAX_BEARERS; i++) { 374 for (i = 0; i < MAX_BEARERS; i++) {
368 b = rcu_dereference_rtnl(tn->bearer_list[i]); 375 b = bearer_get(net, i);
376 if (b)
377 clear_bit_unlock(0, &b->up);
378 }
379 for (i = 0; i < MAX_BEARERS; i++) {
380 b = bearer_get(net, i);
369 if (b) 381 if (b)
370 tipc_reset_bearer(net, b); 382 tipc_reset_bearer(net, b);
371 } 383 }
384 for (i = 0; i < MAX_BEARERS; i++) {
385 b = bearer_get(net, i);
386 if (b)
387 test_and_set_bit_lock(0, &b->up);
388 }
372} 389}
373 390
374/** 391/**
@@ -382,8 +399,9 @@ static void bearer_disable(struct net *net, struct tipc_bearer *b)
382 int bearer_id = b->identity; 399 int bearer_id = b->identity;
383 400
384 pr_info("Disabling bearer <%s>\n", b->name); 401 pr_info("Disabling bearer <%s>\n", b->name);
385 b->media->disable_media(b); 402 clear_bit_unlock(0, &b->up);
386 tipc_node_delete_links(net, bearer_id); 403 tipc_node_delete_links(net, bearer_id);
404 b->media->disable_media(b);
387 RCU_INIT_POINTER(b->media_ptr, NULL); 405 RCU_INIT_POINTER(b->media_ptr, NULL);
388 if (b->link_req) 406 if (b->link_req)
389 tipc_disc_delete(b->link_req); 407 tipc_disc_delete(b->link_req);
@@ -440,22 +458,16 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
440{ 458{
441 struct net_device *dev; 459 struct net_device *dev;
442 int delta; 460 int delta;
443 void *tipc_ptr;
444 461
445 dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr); 462 dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
446 if (!dev) 463 if (!dev)
447 return 0; 464 return 0;
448 465
449 /* Send RESET message even if bearer is detached from device */ 466 delta = SKB_DATA_ALIGN(dev->hard_header_len - skb_headroom(skb));
450 tipc_ptr = rcu_dereference_rtnl(dev->tipc_ptr); 467 if ((delta > 0) && pskb_expand_head(skb, delta, 0, GFP_ATOMIC)) {
451 if (unlikely(!tipc_ptr && !msg_is_reset(buf_msg(skb)))) 468 kfree_skb(skb);
452 goto drop; 469 return 0;
453 470 }
454 delta = dev->hard_header_len - skb_headroom(skb);
455 if ((delta > 0) &&
456 pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC))
457 goto drop;
458
459 skb_reset_network_header(skb); 471 skb_reset_network_header(skb);
460 skb->dev = dev; 472 skb->dev = dev;
461 skb->protocol = htons(ETH_P_TIPC); 473 skb->protocol = htons(ETH_P_TIPC);
@@ -463,9 +475,6 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
463 dev->dev_addr, skb->len); 475 dev->dev_addr, skb->len);
464 dev_queue_xmit(skb); 476 dev_queue_xmit(skb);
465 return 0; 477 return 0;
466drop:
467 kfree_skb(skb);
468 return 0;
469} 478}
470 479
471int tipc_bearer_mtu(struct net *net, u32 bearer_id) 480int tipc_bearer_mtu(struct net *net, u32 bearer_id)
@@ -487,12 +496,12 @@ void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id,
487 struct sk_buff *skb, 496 struct sk_buff *skb,
488 struct tipc_media_addr *dest) 497 struct tipc_media_addr *dest)
489{ 498{
490 struct tipc_net *tn = tipc_net(net); 499 struct tipc_msg *hdr = buf_msg(skb);
491 struct tipc_bearer *b; 500 struct tipc_bearer *b;
492 501
493 rcu_read_lock(); 502 rcu_read_lock();
494 b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); 503 b = bearer_get(net, bearer_id);
495 if (likely(b)) 504 if (likely(b && (test_bit(0, &b->up) || msg_is_reset(hdr))))
496 b->media->send_msg(net, skb, b, dest); 505 b->media->send_msg(net, skb, b, dest);
497 else 506 else
498 kfree_skb(skb); 507 kfree_skb(skb);
@@ -505,7 +514,6 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
505 struct sk_buff_head *xmitq, 514 struct sk_buff_head *xmitq,
506 struct tipc_media_addr *dst) 515 struct tipc_media_addr *dst)
507{ 516{
508 struct tipc_net *tn = net_generic(net, tipc_net_id);
509 struct tipc_bearer *b; 517 struct tipc_bearer *b;
510 struct sk_buff *skb, *tmp; 518 struct sk_buff *skb, *tmp;
511 519
@@ -513,12 +521,15 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
513 return; 521 return;
514 522
515 rcu_read_lock(); 523 rcu_read_lock();
516 b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); 524 b = bearer_get(net, bearer_id);
517 if (unlikely(!b)) 525 if (unlikely(!b))
518 __skb_queue_purge(xmitq); 526 __skb_queue_purge(xmitq);
519 skb_queue_walk_safe(xmitq, skb, tmp) { 527 skb_queue_walk_safe(xmitq, skb, tmp) {
520 __skb_dequeue(xmitq); 528 __skb_dequeue(xmitq);
521 b->media->send_msg(net, skb, b, dst); 529 if (likely(test_bit(0, &b->up) || msg_is_reset(buf_msg(skb))))
530 b->media->send_msg(net, skb, b, dst);
531 else
532 kfree(skb);
522 } 533 }
523 rcu_read_unlock(); 534 rcu_read_unlock();
524} 535}
@@ -535,8 +546,8 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
535 struct tipc_msg *hdr; 546 struct tipc_msg *hdr;
536 547
537 rcu_read_lock(); 548 rcu_read_lock();
538 b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); 549 b = bearer_get(net, bearer_id);
539 if (unlikely(!b)) 550 if (unlikely(!b || !test_bit(0, &b->up)))
540 __skb_queue_purge(xmitq); 551 __skb_queue_purge(xmitq);
541 skb_queue_walk_safe(xmitq, skb, tmp) { 552 skb_queue_walk_safe(xmitq, skb, tmp) {
542 hdr = buf_msg(skb); 553 hdr = buf_msg(skb);
@@ -566,7 +577,8 @@ static int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev,
566 577
567 rcu_read_lock(); 578 rcu_read_lock();
568 b = rcu_dereference_rtnl(dev->tipc_ptr); 579 b = rcu_dereference_rtnl(dev->tipc_ptr);
569 if (likely(b && (skb->pkt_type <= PACKET_BROADCAST))) { 580 if (likely(b && test_bit(0, &b->up) &&
581 (skb->pkt_type <= PACKET_BROADCAST))) {
570 skb->next = NULL; 582 skb->next = NULL;
571 tipc_rcv(dev_net(dev), skb, b); 583 tipc_rcv(dev_net(dev), skb, b);
572 rcu_read_unlock(); 584 rcu_read_unlock();
@@ -591,18 +603,9 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
591{ 603{
592 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 604 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
593 struct net *net = dev_net(dev); 605 struct net *net = dev_net(dev);
594 struct tipc_net *tn = tipc_net(net);
595 struct tipc_bearer *b; 606 struct tipc_bearer *b;
596 int i;
597 607
598 b = rtnl_dereference(dev->tipc_ptr); 608 b = rtnl_dereference(dev->tipc_ptr);
599 if (!b) {
600 for (i = 0; i < MAX_BEARERS; b = NULL, i++) {
601 b = rtnl_dereference(tn->bearer_list[i]);
602 if (b && (b->media_ptr == dev))
603 break;
604 }
605 }
606 if (!b) 609 if (!b)
607 return NOTIFY_DONE; 610 return NOTIFY_DONE;
608 611
@@ -613,11 +616,10 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
613 if (netif_carrier_ok(dev)) 616 if (netif_carrier_ok(dev))
614 break; 617 break;
615 case NETDEV_UP: 618 case NETDEV_UP:
616 rcu_assign_pointer(dev->tipc_ptr, b); 619 test_and_set_bit_lock(0, &b->up);
617 break; 620 break;
618 case NETDEV_GOING_DOWN: 621 case NETDEV_GOING_DOWN:
619 RCU_INIT_POINTER(dev->tipc_ptr, NULL); 622 clear_bit_unlock(0, &b->up);
620 synchronize_net();
621 tipc_reset_bearer(net, b); 623 tipc_reset_bearer(net, b);
622 break; 624 break;
623 case NETDEV_CHANGEMTU: 625 case NETDEV_CHANGEMTU:
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 43757f1f9cb3..83a9abbfe32c 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -150,6 +150,7 @@ struct tipc_bearer {
150 u32 identity; 150 u32 identity;
151 struct tipc_link_req *link_req; 151 struct tipc_link_req *link_req;
152 char net_plane; 152 char net_plane;
153 unsigned long up;
153}; 154};
154 155
155struct tipc_bearer_names { 156struct tipc_bearer_names {
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index b016c011970b..33bdf5449a5e 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -224,7 +224,7 @@ static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb)
224 rcu_read_lock(); 224 rcu_read_lock();
225 b = rcu_dereference_rtnl(ub->bearer); 225 b = rcu_dereference_rtnl(ub->bearer);
226 226
227 if (b) { 227 if (b && test_bit(0, &b->up)) {
228 tipc_rcv(sock_net(sk), skb, b); 228 tipc_rcv(sock_net(sk), skb, b);
229 rcu_read_unlock(); 229 rcu_read_unlock();
230 return 0; 230 return 0;