diff options
author | Jiri Pirko <jpirko@redhat.com> | 2010-06-01 17:52:08 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-02 10:11:15 -0400 |
commit | ab95bfe01f9872459c8678572ccadbf646badad0 (patch) | |
tree | 8e11f94077c9a80f7af52ce3dd50591a686561d7 | |
parent | 20c59de2e6b6bc74bbf714dcd4e720afe8d516cf (diff) |
net: replace hooks in __netif_receive_skb V5
What this patch does is it removes two receive frame hooks (for bridge and for
macvlan) from __netif_receive_skb. These are replaced them with a single
hook for both. It only supports one hook per device because it makes no
sense to do bridging and macvlan on the same device.
Then a network driver (of virtual netdev like macvlan or bridge) can register
an rx_handler for needed net device.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/macvlan.c | 19 | ||||
-rw-r--r-- | include/linux/if_bridge.h | 2 | ||||
-rw-r--r-- | include/linux/if_macvlan.h | 4 | ||||
-rw-r--r-- | include/linux/netdevice.h | 7 | ||||
-rw-r--r-- | net/bridge/br.c | 2 | ||||
-rw-r--r-- | net/bridge/br_if.c | 8 | ||||
-rw-r--r-- | net/bridge/br_input.c | 12 | ||||
-rw-r--r-- | net/bridge/br_private.h | 3 | ||||
-rw-r--r-- | net/core/dev.c | 119 |
9 files changed, 93 insertions, 83 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 87e8d4cb405..53422ce26f7 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c | |||
@@ -145,15 +145,16 @@ static void macvlan_broadcast(struct sk_buff *skb, | |||
145 | } | 145 | } |
146 | 146 | ||
147 | /* called under rcu_read_lock() from netif_receive_skb */ | 147 | /* called under rcu_read_lock() from netif_receive_skb */ |
148 | static struct sk_buff *macvlan_handle_frame(struct macvlan_port *port, | 148 | static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) |
149 | struct sk_buff *skb) | ||
150 | { | 149 | { |
150 | struct macvlan_port *port; | ||
151 | const struct ethhdr *eth = eth_hdr(skb); | 151 | const struct ethhdr *eth = eth_hdr(skb); |
152 | const struct macvlan_dev *vlan; | 152 | const struct macvlan_dev *vlan; |
153 | const struct macvlan_dev *src; | 153 | const struct macvlan_dev *src; |
154 | struct net_device *dev; | 154 | struct net_device *dev; |
155 | unsigned int len; | 155 | unsigned int len; |
156 | 156 | ||
157 | port = rcu_dereference(skb->dev->macvlan_port); | ||
157 | if (is_multicast_ether_addr(eth->h_dest)) { | 158 | if (is_multicast_ether_addr(eth->h_dest)) { |
158 | src = macvlan_hash_lookup(port, eth->h_source); | 159 | src = macvlan_hash_lookup(port, eth->h_source); |
159 | if (!src) | 160 | if (!src) |
@@ -515,6 +516,7 @@ static int macvlan_port_create(struct net_device *dev) | |||
515 | { | 516 | { |
516 | struct macvlan_port *port; | 517 | struct macvlan_port *port; |
517 | unsigned int i; | 518 | unsigned int i; |
519 | int err; | ||
518 | 520 | ||
519 | if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK) | 521 | if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK) |
520 | return -EINVAL; | 522 | return -EINVAL; |
@@ -528,13 +530,21 @@ static int macvlan_port_create(struct net_device *dev) | |||
528 | for (i = 0; i < MACVLAN_HASH_SIZE; i++) | 530 | for (i = 0; i < MACVLAN_HASH_SIZE; i++) |
529 | INIT_HLIST_HEAD(&port->vlan_hash[i]); | 531 | INIT_HLIST_HEAD(&port->vlan_hash[i]); |
530 | rcu_assign_pointer(dev->macvlan_port, port); | 532 | rcu_assign_pointer(dev->macvlan_port, port); |
531 | return 0; | 533 | |
534 | err = netdev_rx_handler_register(dev, macvlan_handle_frame); | ||
535 | if (err) { | ||
536 | rcu_assign_pointer(dev->macvlan_port, NULL); | ||
537 | kfree(port); | ||
538 | } | ||
539 | |||
540 | return err; | ||
532 | } | 541 | } |
533 | 542 | ||
534 | static void macvlan_port_destroy(struct net_device *dev) | 543 | static void macvlan_port_destroy(struct net_device *dev) |
535 | { | 544 | { |
536 | struct macvlan_port *port = dev->macvlan_port; | 545 | struct macvlan_port *port = dev->macvlan_port; |
537 | 546 | ||
547 | netdev_rx_handler_unregister(dev); | ||
538 | rcu_assign_pointer(dev->macvlan_port, NULL); | 548 | rcu_assign_pointer(dev->macvlan_port, NULL); |
539 | synchronize_rcu(); | 549 | synchronize_rcu(); |
540 | kfree(port); | 550 | kfree(port); |
@@ -767,14 +777,12 @@ static int __init macvlan_init_module(void) | |||
767 | int err; | 777 | int err; |
768 | 778 | ||
769 | register_netdevice_notifier(&macvlan_notifier_block); | 779 | register_netdevice_notifier(&macvlan_notifier_block); |
770 | macvlan_handle_frame_hook = macvlan_handle_frame; | ||
771 | 780 | ||
772 | err = macvlan_link_register(&macvlan_link_ops); | 781 | err = macvlan_link_register(&macvlan_link_ops); |
773 | if (err < 0) | 782 | if (err < 0) |
774 | goto err1; | 783 | goto err1; |
775 | return 0; | 784 | return 0; |
776 | err1: | 785 | err1: |
777 | macvlan_handle_frame_hook = NULL; | ||
778 | unregister_netdevice_notifier(&macvlan_notifier_block); | 786 | unregister_netdevice_notifier(&macvlan_notifier_block); |
779 | return err; | 787 | return err; |
780 | } | 788 | } |
@@ -782,7 +790,6 @@ err1: | |||
782 | static void __exit macvlan_cleanup_module(void) | 790 | static void __exit macvlan_cleanup_module(void) |
783 | { | 791 | { |
784 | rtnl_link_unregister(&macvlan_link_ops); | 792 | rtnl_link_unregister(&macvlan_link_ops); |
785 | macvlan_handle_frame_hook = NULL; | ||
786 | unregister_netdevice_notifier(&macvlan_notifier_block); | 793 | unregister_netdevice_notifier(&macvlan_notifier_block); |
787 | } | 794 | } |
788 | 795 | ||
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 938b7e81df9..0d241a5c490 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h | |||
@@ -102,8 +102,6 @@ struct __fdb_entry { | |||
102 | #include <linux/netdevice.h> | 102 | #include <linux/netdevice.h> |
103 | 103 | ||
104 | extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); | 104 | extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); |
105 | extern struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p, | ||
106 | struct sk_buff *skb); | ||
107 | extern int (*br_should_route_hook)(struct sk_buff *skb); | 105 | extern int (*br_should_route_hook)(struct sk_buff *skb); |
108 | 106 | ||
109 | #endif | 107 | #endif |
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h index 9ea047aca79..c26a0e4f0ce 100644 --- a/include/linux/if_macvlan.h +++ b/include/linux/if_macvlan.h | |||
@@ -84,8 +84,4 @@ extern int macvlan_link_register(struct rtnl_link_ops *ops); | |||
84 | extern netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, | 84 | extern netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, |
85 | struct net_device *dev); | 85 | struct net_device *dev); |
86 | 86 | ||
87 | |||
88 | extern struct sk_buff *(*macvlan_handle_frame_hook)(struct macvlan_port *, | ||
89 | struct sk_buff *); | ||
90 | |||
91 | #endif /* _LINUX_IF_MACVLAN_H */ | 87 | #endif /* _LINUX_IF_MACVLAN_H */ |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index bd6b75317d5..5156b806924 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -381,6 +381,8 @@ enum gro_result { | |||
381 | }; | 381 | }; |
382 | typedef enum gro_result gro_result_t; | 382 | typedef enum gro_result gro_result_t; |
383 | 383 | ||
384 | typedef struct sk_buff *rx_handler_func_t(struct sk_buff *skb); | ||
385 | |||
384 | extern void __napi_schedule(struct napi_struct *n); | 386 | extern void __napi_schedule(struct napi_struct *n); |
385 | 387 | ||
386 | static inline int napi_disable_pending(struct napi_struct *n) | 388 | static inline int napi_disable_pending(struct napi_struct *n) |
@@ -957,6 +959,7 @@ struct net_device { | |||
957 | #endif | 959 | #endif |
958 | 960 | ||
959 | struct netdev_queue rx_queue; | 961 | struct netdev_queue rx_queue; |
962 | rx_handler_func_t *rx_handler; | ||
960 | 963 | ||
961 | struct netdev_queue *_tx ____cacheline_aligned_in_smp; | 964 | struct netdev_queue *_tx ____cacheline_aligned_in_smp; |
962 | 965 | ||
@@ -1689,6 +1692,10 @@ static inline void napi_free_frags(struct napi_struct *napi) | |||
1689 | napi->skb = NULL; | 1692 | napi->skb = NULL; |
1690 | } | 1693 | } |
1691 | 1694 | ||
1695 | extern int netdev_rx_handler_register(struct net_device *dev, | ||
1696 | rx_handler_func_t *rx_handler); | ||
1697 | extern void netdev_rx_handler_unregister(struct net_device *dev); | ||
1698 | |||
1692 | extern void netif_nit_deliver(struct sk_buff *skb); | 1699 | extern void netif_nit_deliver(struct sk_buff *skb); |
1693 | extern int dev_valid_name(const char *name); | 1700 | extern int dev_valid_name(const char *name); |
1694 | extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *); | 1701 | extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *); |
diff --git a/net/bridge/br.c b/net/bridge/br.c index 76357b54775..c8436fa3134 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c | |||
@@ -63,7 +63,6 @@ static int __init br_init(void) | |||
63 | goto err_out4; | 63 | goto err_out4; |
64 | 64 | ||
65 | brioctl_set(br_ioctl_deviceless_stub); | 65 | brioctl_set(br_ioctl_deviceless_stub); |
66 | br_handle_frame_hook = br_handle_frame; | ||
67 | 66 | ||
68 | #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) | 67 | #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) |
69 | br_fdb_test_addr_hook = br_fdb_test_addr; | 68 | br_fdb_test_addr_hook = br_fdb_test_addr; |
@@ -100,7 +99,6 @@ static void __exit br_deinit(void) | |||
100 | br_fdb_test_addr_hook = NULL; | 99 | br_fdb_test_addr_hook = NULL; |
101 | #endif | 100 | #endif |
102 | 101 | ||
103 | br_handle_frame_hook = NULL; | ||
104 | br_fdb_fini(); | 102 | br_fdb_fini(); |
105 | } | 103 | } |
106 | 104 | ||
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 18b245e2c00..d9242342837 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -147,6 +147,7 @@ static void del_nbp(struct net_bridge_port *p) | |||
147 | 147 | ||
148 | list_del_rcu(&p->list); | 148 | list_del_rcu(&p->list); |
149 | 149 | ||
150 | netdev_rx_handler_unregister(dev); | ||
150 | rcu_assign_pointer(dev->br_port, NULL); | 151 | rcu_assign_pointer(dev->br_port, NULL); |
151 | 152 | ||
152 | br_multicast_del_port(p); | 153 | br_multicast_del_port(p); |
@@ -429,6 +430,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
429 | goto err2; | 430 | goto err2; |
430 | 431 | ||
431 | rcu_assign_pointer(dev->br_port, p); | 432 | rcu_assign_pointer(dev->br_port, p); |
433 | |||
434 | err = netdev_rx_handler_register(dev, br_handle_frame); | ||
435 | if (err) | ||
436 | goto err3; | ||
437 | |||
432 | dev_disable_lro(dev); | 438 | dev_disable_lro(dev); |
433 | 439 | ||
434 | list_add_rcu(&p->list, &br->port_list); | 440 | list_add_rcu(&p->list, &br->port_list); |
@@ -451,6 +457,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
451 | br_netpoll_enable(br, dev); | 457 | br_netpoll_enable(br, dev); |
452 | 458 | ||
453 | return 0; | 459 | return 0; |
460 | err3: | ||
461 | rcu_assign_pointer(dev->br_port, NULL); | ||
454 | err2: | 462 | err2: |
455 | br_fdb_delete_by_port(br, p, 1); | 463 | br_fdb_delete_by_port(br, p, 1); |
456 | err1: | 464 | err1: |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index d36e700f7a2..99647d8f95c 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -131,15 +131,19 @@ static inline int is_link_local(const unsigned char *dest) | |||
131 | } | 131 | } |
132 | 132 | ||
133 | /* | 133 | /* |
134 | * Called via br_handle_frame_hook. | ||
135 | * Return NULL if skb is handled | 134 | * Return NULL if skb is handled |
136 | * note: already called with rcu_read_lock (preempt_disabled) | 135 | * note: already called with rcu_read_lock (preempt_disabled) from |
136 | * netif_receive_skb | ||
137 | */ | 137 | */ |
138 | struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) | 138 | struct sk_buff *br_handle_frame(struct sk_buff *skb) |
139 | { | 139 | { |
140 | struct net_bridge_port *p; | ||
140 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 141 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
141 | int (*rhook)(struct sk_buff *skb); | 142 | int (*rhook)(struct sk_buff *skb); |
142 | 143 | ||
144 | if (skb->pkt_type == PACKET_LOOPBACK) | ||
145 | return skb; | ||
146 | |||
143 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) | 147 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) |
144 | goto drop; | 148 | goto drop; |
145 | 149 | ||
@@ -147,6 +151,8 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) | |||
147 | if (!skb) | 151 | if (!skb) |
148 | return NULL; | 152 | return NULL; |
149 | 153 | ||
154 | p = rcu_dereference(skb->dev->br_port); | ||
155 | |||
150 | if (unlikely(is_link_local(dest))) { | 156 | if (unlikely(is_link_local(dest))) { |
151 | /* Pause frames shouldn't be passed up by driver anyway */ | 157 | /* Pause frames shouldn't be passed up by driver anyway */ |
152 | if (skb->protocol == htons(ETH_P_PAUSE)) | 158 | if (skb->protocol == htons(ETH_P_PAUSE)) |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 0f4a74bc6a9..c83519b555b 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -331,8 +331,7 @@ extern void br_features_recompute(struct net_bridge *br); | |||
331 | 331 | ||
332 | /* br_input.c */ | 332 | /* br_input.c */ |
333 | extern int br_handle_frame_finish(struct sk_buff *skb); | 333 | extern int br_handle_frame_finish(struct sk_buff *skb); |
334 | extern struct sk_buff *br_handle_frame(struct net_bridge_port *p, | 334 | extern struct sk_buff *br_handle_frame(struct sk_buff *skb); |
335 | struct sk_buff *skb); | ||
336 | 335 | ||
337 | /* br_ioctl.c */ | 336 | /* br_ioctl.c */ |
338 | extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 337 | extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
diff --git a/net/core/dev.c b/net/core/dev.c index ffca5c1066f..ec01a5998d7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -2604,70 +2604,14 @@ static inline int deliver_skb(struct sk_buff *skb, | |||
2604 | return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); | 2604 | return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); |
2605 | } | 2605 | } |
2606 | 2606 | ||
2607 | #if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE) | 2607 | #if (defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)) && \ |
2608 | 2608 | (defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)) | |
2609 | #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) | ||
2610 | /* This hook is defined here for ATM LANE */ | 2609 | /* This hook is defined here for ATM LANE */ |
2611 | int (*br_fdb_test_addr_hook)(struct net_device *dev, | 2610 | int (*br_fdb_test_addr_hook)(struct net_device *dev, |
2612 | unsigned char *addr) __read_mostly; | 2611 | unsigned char *addr) __read_mostly; |
2613 | EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook); | 2612 | EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook); |
2614 | #endif | 2613 | #endif |
2615 | 2614 | ||
2616 | /* | ||
2617 | * If bridge module is loaded call bridging hook. | ||
2618 | * returns NULL if packet was consumed. | ||
2619 | */ | ||
2620 | struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p, | ||
2621 | struct sk_buff *skb) __read_mostly; | ||
2622 | EXPORT_SYMBOL_GPL(br_handle_frame_hook); | ||
2623 | |||
2624 | static inline struct sk_buff *handle_bridge(struct sk_buff *skb, | ||
2625 | struct packet_type **pt_prev, int *ret, | ||
2626 | struct net_device *orig_dev) | ||
2627 | { | ||
2628 | struct net_bridge_port *port; | ||
2629 | |||
2630 | if (skb->pkt_type == PACKET_LOOPBACK || | ||
2631 | (port = rcu_dereference(skb->dev->br_port)) == NULL) | ||
2632 | return skb; | ||
2633 | |||
2634 | if (*pt_prev) { | ||
2635 | *ret = deliver_skb(skb, *pt_prev, orig_dev); | ||
2636 | *pt_prev = NULL; | ||
2637 | } | ||
2638 | |||
2639 | return br_handle_frame_hook(port, skb); | ||
2640 | } | ||
2641 | #else | ||
2642 | #define handle_bridge(skb, pt_prev, ret, orig_dev) (skb) | ||
2643 | #endif | ||
2644 | |||
2645 | #if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE) | ||
2646 | struct sk_buff *(*macvlan_handle_frame_hook)(struct macvlan_port *p, | ||
2647 | struct sk_buff *skb) __read_mostly; | ||
2648 | EXPORT_SYMBOL_GPL(macvlan_handle_frame_hook); | ||
2649 | |||
2650 | static inline struct sk_buff *handle_macvlan(struct sk_buff *skb, | ||
2651 | struct packet_type **pt_prev, | ||
2652 | int *ret, | ||
2653 | struct net_device *orig_dev) | ||
2654 | { | ||
2655 | struct macvlan_port *port; | ||
2656 | |||
2657 | port = rcu_dereference(skb->dev->macvlan_port); | ||
2658 | if (!port) | ||
2659 | return skb; | ||
2660 | |||
2661 | if (*pt_prev) { | ||
2662 | *ret = deliver_skb(skb, *pt_prev, orig_dev); | ||
2663 | *pt_prev = NULL; | ||
2664 | } | ||
2665 | return macvlan_handle_frame_hook(port, skb); | ||
2666 | } | ||
2667 | #else | ||
2668 | #define handle_macvlan(skb, pt_prev, ret, orig_dev) (skb) | ||
2669 | #endif | ||
2670 | |||
2671 | #ifdef CONFIG_NET_CLS_ACT | 2615 | #ifdef CONFIG_NET_CLS_ACT |
2672 | /* TODO: Maybe we should just force sch_ingress to be compiled in | 2616 | /* TODO: Maybe we should just force sch_ingress to be compiled in |
2673 | * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions | 2617 | * when CONFIG_NET_CLS_ACT is? otherwise some useless instructions |
@@ -2763,6 +2707,47 @@ void netif_nit_deliver(struct sk_buff *skb) | |||
2763 | rcu_read_unlock(); | 2707 | rcu_read_unlock(); |
2764 | } | 2708 | } |
2765 | 2709 | ||
2710 | /** | ||
2711 | * netdev_rx_handler_register - register receive handler | ||
2712 | * @dev: device to register a handler for | ||
2713 | * @rx_handler: receive handler to register | ||
2714 | * | ||
2715 | * Register a receive hander for a device. This handler will then be | ||
2716 | * called from __netif_receive_skb. A negative errno code is returned | ||
2717 | * on a failure. | ||
2718 | * | ||
2719 | * The caller must hold the rtnl_mutex. | ||
2720 | */ | ||
2721 | int netdev_rx_handler_register(struct net_device *dev, | ||
2722 | rx_handler_func_t *rx_handler) | ||
2723 | { | ||
2724 | ASSERT_RTNL(); | ||
2725 | |||
2726 | if (dev->rx_handler) | ||
2727 | return -EBUSY; | ||
2728 | |||
2729 | rcu_assign_pointer(dev->rx_handler, rx_handler); | ||
2730 | |||
2731 | return 0; | ||
2732 | } | ||
2733 | EXPORT_SYMBOL_GPL(netdev_rx_handler_register); | ||
2734 | |||
2735 | /** | ||
2736 | * netdev_rx_handler_unregister - unregister receive handler | ||
2737 | * @dev: device to unregister a handler from | ||
2738 | * | ||
2739 | * Unregister a receive hander from a device. | ||
2740 | * | ||
2741 | * The caller must hold the rtnl_mutex. | ||
2742 | */ | ||
2743 | void netdev_rx_handler_unregister(struct net_device *dev) | ||
2744 | { | ||
2745 | |||
2746 | ASSERT_RTNL(); | ||
2747 | rcu_assign_pointer(dev->rx_handler, NULL); | ||
2748 | } | ||
2749 | EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); | ||
2750 | |||
2766 | static inline void skb_bond_set_mac_by_master(struct sk_buff *skb, | 2751 | static inline void skb_bond_set_mac_by_master(struct sk_buff *skb, |
2767 | struct net_device *master) | 2752 | struct net_device *master) |
2768 | { | 2753 | { |
@@ -2815,6 +2800,7 @@ EXPORT_SYMBOL(__skb_bond_should_drop); | |||
2815 | static int __netif_receive_skb(struct sk_buff *skb) | 2800 | static int __netif_receive_skb(struct sk_buff *skb) |
2816 | { | 2801 | { |
2817 | struct packet_type *ptype, *pt_prev; | 2802 | struct packet_type *ptype, *pt_prev; |
2803 | rx_handler_func_t *rx_handler; | ||
2818 | struct net_device *orig_dev; | 2804 | struct net_device *orig_dev; |
2819 | struct net_device *master; | 2805 | struct net_device *master; |
2820 | struct net_device *null_or_orig; | 2806 | struct net_device *null_or_orig; |
@@ -2877,12 +2863,17 @@ static int __netif_receive_skb(struct sk_buff *skb) | |||
2877 | ncls: | 2863 | ncls: |
2878 | #endif | 2864 | #endif |
2879 | 2865 | ||
2880 | skb = handle_bridge(skb, &pt_prev, &ret, orig_dev); | 2866 | /* Handle special case of bridge or macvlan */ |
2881 | if (!skb) | 2867 | rx_handler = rcu_dereference(skb->dev->rx_handler); |
2882 | goto out; | 2868 | if (rx_handler) { |
2883 | skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev); | 2869 | if (pt_prev) { |
2884 | if (!skb) | 2870 | ret = deliver_skb(skb, pt_prev, orig_dev); |
2885 | goto out; | 2871 | pt_prev = NULL; |
2872 | } | ||
2873 | skb = rx_handler(skb); | ||
2874 | if (!skb) | ||
2875 | goto out; | ||
2876 | } | ||
2886 | 2877 | ||
2887 | /* | 2878 | /* |
2888 | * Make sure frames received on VLAN interfaces stacked on | 2879 | * Make sure frames received on VLAN interfaces stacked on |