Release 4.15 net/bridge/br_input.c
/*
* Handle incoming frames
* Linux ethernet bridge
*
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/netfilter_bridge.h>
#include <linux/neighbour.h>
#include <net/arp.h>
#include <linux/export.h>
#include <linux/rculist.h>
#include "br_private.h"
#include "br_private_tunnel.h"
/* Hook for brouter */
br_should_route_hook_t __rcu *br_should_route_hook __read_mostly;
EXPORT_SYMBOL(br_should_route_hook);
static int
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
{
br_drop_fake_rtable(skb);
return netif_receive_skb(skb);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eric W. Biedermann | 27 | 84.38% | 2 | 66.67% |
Florian Westphal | 5 | 15.62% | 1 | 33.33% |
Total | 32 | 100.00% | 3 | 100.00% |
static int br_pass_frame_up(struct sk_buff *skb)
{
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
struct net_bridge *br = netdev_priv(brdev);
struct net_bridge_vlan_group *vg;
struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
u64_stats_update_begin(&brstats->syncp);
brstats->rx_packets++;
brstats->rx_bytes += skb->len;
u64_stats_update_end(&brstats->syncp);
vg = br_vlan_group_rcu(br);
/* Bridge is just like any other port. Make sure the
* packet is allowed except in promisc modue when someone
* may be running packet capture.
*/
if (!(brdev->flags & IFF_PROMISC) &&
!br_allowed_egress(vg, skb)) {
kfree_skb(skb);
return NET_RX_DROP;
}
indev = skb->dev;
skb->dev = brdev;
skb = br_handle_vlan(br, NULL, vg, skb);
if (!skb)
return NET_RX_DROP;
/* update the multicast stats if the packet is IGMP/MLD */
br_multicast_count(br, NULL, skb, br_multicast_igmp_type(skb),
BR_MCAST_DIR_TX);
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN,
dev_net(indev), NULL, skb, indev, NULL,
br_netif_receive_skb);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vlad Yasevich | 63 | 32.81% | 3 | 16.67% |
Nikolay Aleksandrov | 27 | 14.06% | 3 | 16.67% |
Linus Torvalds (pre-git) | 24 | 12.50% | 1 | 5.56% |
Stephen Hemminger | 21 | 10.94% | 1 | 5.56% |
Eric Dumazet | 16 | 8.33% | 1 | 5.56% |
Linus Torvalds | 13 | 6.77% | 1 | 5.56% |
Herbert Xu | 8 | 4.17% | 1 | 5.56% |
Pavel Emelyanov | 8 | 4.17% | 1 | 5.56% |
Eric W. Biedermann | 6 | 3.12% | 2 | 11.11% |
Roopa Prabhu | 2 | 1.04% | 1 | 5.56% |
David S. Miller | 2 | 1.04% | 1 | 5.56% |
Li RongQing | 1 | 0.52% | 1 | 5.56% |
Jan Engelhardt | 1 | 0.52% | 1 | 5.56% |
Total | 192 | 100.00% | 18 | 100.00% |
/* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
enum br_pkt_type pkt_type = BR_PKT_UNICAST;
struct net_bridge_fdb_entry *dst = NULL;
struct net_bridge_mdb_entry *mdst;
bool local_rcv, mcast_hit = false;
const unsigned char *dest;
struct net_bridge *br;
u16 vid = 0;
if (!p || p->state == BR_STATE_DISABLED)
goto drop;
if (!br_allowed_ingress(p->br, nbp_vlan_group_rcu(p), skb, &vid))
goto out;
nbp_switchdev_frame_mark(p, skb);
/* insert into forwarding database after filtering to avoid spoofing */
br = p->br;
if (p->flags & BR_LEARNING)
br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);
local_rcv = !!(br->dev->flags & IFF_PROMISC);
dest = eth_hdr(skb)->h_dest;
if (is_multicast_ether_addr(dest)) {
/* by definition the broadcast is also a multicast address */
if (is_broadcast_ether_addr(dest)) {
pkt_type = BR_PKT_BROADCAST;
local_rcv = true;
} else {
pkt_type = BR_PKT_MULTICAST;
if (br_multicast_rcv(br, p, skb, vid))
goto drop;
}
}
if (p->state == BR_STATE_LEARNING)
goto drop;
BR_INPUT_SKB_CB(skb)->brdev = br->dev;
if (IS_ENABLED(CONFIG_INET) &&
(skb->protocol == htons(ETH_P_ARP) ||
skb->protocol == htons(ETH_P_RARP))) {
br_do_proxy_suppress_arp(skb, br, vid, p);
} else if (IS_ENABLED(CONFIG_IPV6) &&
skb->protocol == htons(ETH_P_IPV6) &&
br->neigh_suppress_enabled &&
pskb_may_pull(skb, sizeof(struct ipv6hdr) +
sizeof(struct nd_msg)) &&
ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
struct nd_msg *msg, _msg;
msg = br_is_nd_neigh_msg(skb, &_msg);
if (msg)
br_do_suppress_nd(skb, br, vid, p, msg);
}
switch (pkt_type) {
case BR_PKT_MULTICAST:
mdst = br_mdb_get(br, skb, vid);
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
br_multicast_querier_exists(br, eth_hdr(skb))) {
if ((mdst && mdst->host_joined) ||
br_multicast_is_router(br)) {
local_rcv = true;
br->dev->stats.multicast++;
}
mcast_hit = true;
} else {
local_rcv = true;
br->dev->stats.multicast++;
}
break;
case BR_PKT_UNICAST:
dst = br_fdb_find_rcu(br, dest, vid);
default:
break;
}
if (dst) {
unsigned long now = jiffies;
if (dst->is_local)
return br_pass_frame_up(skb);
if (now != dst->used)
dst->used = now;
br_forward(dst->dst, skb, local_rcv, false);
} else {
if (!mcast_hit)
br_flood(br, skb, pkt_type, local_rcv, false);
else
br_multicast_flood(mdst, skb, local_rcv, false);
}
if (local_rcv)
return br_pass_frame_up(skb);
out:
return 0;
drop:
kfree_skb(skb);
goto out;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Nikolay Aleksandrov | 163 | 27.77% | 10 | 20.00% |
Roopa Prabhu | 97 | 16.52% | 2 | 4.00% |
Herbert Xu | 90 | 15.33% | 6 | 12.00% |
Stephen Hemminger | 86 | 14.65% | 7 | 14.00% |
Linus Torvalds (pre-git) | 43 | 7.33% | 2 | 4.00% |
Vlad Yasevich | 34 | 5.79% | 6 | 12.00% |
Kyeyoon Park | 17 | 2.90% | 1 | 2.00% |
Linus Lüssing | 12 | 2.04% | 2 | 4.00% |
Linus Torvalds | 8 | 1.36% | 1 | 2.00% |
Ido Schimmel | 7 | 1.19% | 1 | 2.00% |
Arnd Bergmann | 5 | 0.85% | 1 | 2.00% |
Eric W. Biedermann | 5 | 0.85% | 1 | 2.00% |
David S. Miller | 5 | 0.85% | 1 | 2.00% |
Pavel Emelyanov | 3 | 0.51% | 1 | 2.00% |
Toshiaki Makita | 3 | 0.51% | 2 | 4.00% |
Jouni Malinen | 3 | 0.51% | 1 | 2.00% |
Américo Wang | 2 | 0.34% | 1 | 2.00% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 0.17% | 1 | 2.00% |
Andrew Lunn | 1 | 0.17% | 1 | 2.00% |
Jiri Pirko | 1 | 0.17% | 1 | 2.00% |
Michael Braun | 1 | 0.17% | 1 | 2.00% |
Total | 587 | 100.00% | 50 | 100.00% |
EXPORT_SYMBOL_GPL(br_handle_frame_finish);
static void __br_handle_local_finish(struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
u16 vid = 0;
/* check if vlan is allowed, to avoid spoofing */
if (p->flags & BR_LEARNING && br_should_learn(p, skb, &vid))
br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Stephen Hemminger | 35 | 52.24% | 1 | 14.29% |
Vlad Yasevich | 15 | 22.39% | 2 | 28.57% |
Toshiaki Makita | 13 | 19.40% | 2 | 28.57% |
Ido Schimmel | 3 | 4.48% | 1 | 14.29% |
Jiri Pirko | 1 | 1.49% | 1 | 14.29% |
Total | 67 | 100.00% | 7 | 100.00% |
/* note: already called with rcu_read_lock */
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
__br_handle_local_finish(skb);
BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
br_pass_frame_up(skb);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ido Schimmel | 37 | 62.71% | 1 | 33.33% |
Florian Westphal | 18 | 30.51% | 1 | 33.33% |
Stephen Hemminger | 4 | 6.78% | 1 | 33.33% |
Total | 59 | 100.00% | 3 | 100.00% |
/*
* Return NULL if skb is handled
* note: already called with rcu_read_lock
*/
rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
{
struct net_bridge_port *p;
struct sk_buff *skb = *pskb;
const unsigned char *dest = eth_hdr(skb)->h_dest;
br_should_route_hook_t *rhook;
if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
return RX_HANDLER_PASS;
if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
goto drop;
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
return RX_HANDLER_CONSUMED;
p = br_port_get_rcu(skb->dev);
if (p->flags & BR_VLAN_TUNNEL) {
if (br_handle_ingress_vlan_tunnel(skb, p,
nbp_vlan_group_rcu(p)))
goto drop;
}
if (unlikely(is_link_local_ether_addr(dest))) {
u16 fwd_mask = p->br->group_fwd_mask_required;
/*
* See IEEE 802.1D Table 7-10 Reserved addresses
*
* Assignment Value
* Bridge Group Address 01-80-C2-00-00-00
* (MAC Control) 802.3 01-80-C2-00-00-01
* (Link Aggregation) 802.3 01-80-C2-00-00-02
* 802.1X PAE address 01-80-C2-00-00-03
*
* 802.1AB LLDP 01-80-C2-00-00-0E
*
* Others reserved for future standardization
*/
fwd_mask |= p->group_fwd_mask;
switch (dest[5]) {
case 0x00: /* Bridge Group Address */
/* If STP is turned off,
then must forward to keep loop detection */
if (p->br->stp_enabled == BR_NO_STP ||
fwd_mask & (1u << dest[5]))
goto forward;
*pskb = skb;
__br_handle_local_finish(skb);
return RX_HANDLER_PASS;
case 0x01: /* IEEE MAC (Pause) */
goto drop;
case 0x0E: /* 802.1AB LLDP */
fwd_mask |= p->br->group_fwd_mask;
if (fwd_mask & (1u << dest[5]))
goto forward;
*pskb = skb;
__br_handle_local_finish(skb);
return RX_HANDLER_PASS;
default:
/* Allow selective forwarding for most other protocols */
fwd_mask |= p->br->group_fwd_mask;
if (fwd_mask & (1u << dest[5]))
goto forward;
}
/* Deliver packet to local host only */
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, dev_net(skb->dev),
NULL, skb, skb->dev, NULL, br_handle_local_finish);
return RX_HANDLER_CONSUMED;
}
forward:
switch (p->state) {
case BR_STATE_FORWARDING:
rhook = rcu_dereference(br_should_route_hook);
if (rhook) {
if ((*rhook)(skb)) {
*pskb = skb;
return RX_HANDLER_PASS;
}
dest = eth_hdr(skb)->h_dest;
}
/* fall through */
case BR_STATE_LEARNING:
if (ether_addr_equal(p->br->dev->dev_addr, dest))
skb->pkt_type = PACKET_HOST;
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
dev_net(skb->dev), NULL, skb, skb->dev, NULL,
br_handle_frame_finish);
break;
default:
drop:
kfree_skb(skb);
}
return RX_HANDLER_CONSUMED;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Stephen Hemminger | 112 | 26.35% | 12 | 31.58% |
Ido Schimmel | 54 | 12.71% | 2 | 5.26% |
Jiri Pirko | 49 | 11.53% | 3 | 7.89% |
Linus Torvalds | 45 | 10.59% | 2 | 5.26% |
Bart De Schuymer | 27 | 6.35% | 3 | 7.89% |
Roopa Prabhu | 27 | 6.35% | 1 | 2.63% |
Toshiaki Makita | 26 | 6.12% | 1 | 2.63% |
Herbert Xu | 16 | 3.76% | 1 | 2.63% |
Eric W. Biedermann | 14 | 3.29% | 1 | 2.63% |
Pavel Emelyanov | 11 | 2.59% | 1 | 2.63% |
Arnaldo Carvalho de Melo | 9 | 2.12% | 1 | 2.63% |
Linus Torvalds (pre-git) | 8 | 1.88% | 1 | 2.63% |
David S. Miller | 8 | 1.88% | 2 | 5.26% |
Nikolay Aleksandrov | 6 | 1.41% | 1 | 2.63% |
Eric Dumazet | 5 | 1.18% | 1 | 2.63% |
Simon Horman | 3 | 0.71% | 1 | 2.63% |
Jan Engelhardt | 2 | 0.47% | 1 | 2.63% |
Ben Hutchings | 1 | 0.24% | 1 | 2.63% |
Florian Westphal | 1 | 0.24% | 1 | 2.63% |
Joe Perches | 1 | 0.24% | 1 | 2.63% |
Total | 425 | 100.00% | 38 | 100.00% |
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Stephen Hemminger | 259 | 18.29% | 20 | 20.20% |
Nikolay Aleksandrov | 196 | 13.84% | 13 | 13.13% |
Roopa Prabhu | 129 | 9.11% | 3 | 3.03% |
Vlad Yasevich | 115 | 8.12% | 8 | 8.08% |
Herbert Xu | 114 | 8.05% | 7 | 7.07% |
Ido Schimmel | 102 | 7.20% | 3 | 3.03% |
Linus Torvalds (pre-git) | 87 | 6.14% | 2 | 2.02% |
Linus Torvalds | 69 | 4.87% | 2 | 2.02% |
Eric W. Biedermann | 52 | 3.67% | 3 | 3.03% |
Jiri Pirko | 51 | 3.60% | 3 | 3.03% |
Toshiaki Makita | 42 | 2.97% | 4 | 4.04% |
Eric Dumazet | 33 | 2.33% | 2 | 2.02% |
Bart De Schuymer | 27 | 1.91% | 3 | 3.03% |
Florian Westphal | 24 | 1.69% | 2 | 2.02% |
Kyeyoon Park | 23 | 1.62% | 1 | 1.01% |
Pavel Emelyanov | 22 | 1.55% | 2 | 2.02% |
David S. Miller | 16 | 1.13% | 3 | 3.03% |
Linus Lüssing | 12 | 0.85% | 2 | 2.02% |
Arnaldo Carvalho de Melo | 9 | 0.64% | 1 | 1.01% |
Pablo Neira Ayuso | 5 | 0.35% | 1 | 1.01% |
Arnd Bergmann | 5 | 0.35% | 1 | 1.01% |
Simon Horman | 3 | 0.21% | 1 | 1.01% |
Jouni Malinen | 3 | 0.21% | 1 | 1.01% |
Jan Engelhardt | 3 | 0.21% | 1 | 1.01% |
Tejun Heo | 3 | 0.21% | 1 | 1.01% |
Paul Gortmaker | 3 | 0.21% | 1 | 1.01% |
Américo Wang | 2 | 0.14% | 1 | 1.01% |
Joe Perches | 1 | 0.07% | 1 | 1.01% |
Andrew Lunn | 1 | 0.07% | 1 | 1.01% |
Michael Braun | 1 | 0.07% | 1 | 1.01% |
Adrian Bunk | 1 | 0.07% | 1 | 1.01% |
Li RongQing | 1 | 0.07% | 1 | 1.01% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 0.07% | 1 | 1.01% |
Ben Hutchings | 1 | 0.07% | 1 | 1.01% |
Total | 1416 | 100.00% | 99 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.