18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Forwarding decision 48c2ecf20Sopenharmony_ci * Linux ethernet bridge 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Authors: 78c2ecf20Sopenharmony_ci * Lennert Buytenhek <buytenh@gnu.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 148c2ecf20Sopenharmony_ci#include <linux/netpoll.h> 158c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 168c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 178c2ecf20Sopenharmony_ci#include <linux/netfilter_bridge.h> 188c2ecf20Sopenharmony_ci#include "br_private.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* Don't forward packets to originating port or forwarding disabled */ 218c2ecf20Sopenharmony_cistatic inline int should_deliver(const struct net_bridge_port *p, 228c2ecf20Sopenharmony_ci const struct sk_buff *skb) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct net_bridge_vlan_group *vg; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci vg = nbp_vlan_group_rcu(p); 278c2ecf20Sopenharmony_ci return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) && 288c2ecf20Sopenharmony_ci p->state == BR_STATE_FORWARDING && br_allowed_egress(vg, skb) && 298c2ecf20Sopenharmony_ci nbp_switchdev_allowed_egress(p, skb) && 308c2ecf20Sopenharmony_ci !br_skb_isolated(p, skb); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciint br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci skb_push(skb, ETH_HLEN); 368c2ecf20Sopenharmony_ci if (!is_skb_forwardable(skb->dev, skb)) 378c2ecf20Sopenharmony_ci goto drop; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci br_drop_fake_rtable(skb); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL && 428c2ecf20Sopenharmony_ci (skb->protocol == htons(ETH_P_8021Q) || 438c2ecf20Sopenharmony_ci skb->protocol == htons(ETH_P_8021AD))) { 448c2ecf20Sopenharmony_ci int depth; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (!vlan_get_protocol_and_depth(skb, skb->protocol, &depth)) 478c2ecf20Sopenharmony_ci goto drop; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci skb_set_network_header(skb, depth); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci dev_queue_xmit(skb); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cidrop: 578c2ecf20Sopenharmony_ci kfree_skb(skb); 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(br_dev_queue_push_xmit); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciint br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci skb->tstamp = 0; 658c2ecf20Sopenharmony_ci return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, 668c2ecf20Sopenharmony_ci net, sk, skb, NULL, skb->dev, 678c2ecf20Sopenharmony_ci br_dev_queue_push_xmit); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(br_forward_finish); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void __br_forward(const struct net_bridge_port *to, 738c2ecf20Sopenharmony_ci struct sk_buff *skb, bool local_orig) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct net_bridge_vlan_group *vg; 768c2ecf20Sopenharmony_ci struct net_device *indev; 778c2ecf20Sopenharmony_ci struct net *net; 788c2ecf20Sopenharmony_ci int br_hook; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci vg = nbp_vlan_group_rcu(to); 818c2ecf20Sopenharmony_ci skb = br_handle_vlan(to->br, to, vg, skb); 828c2ecf20Sopenharmony_ci if (!skb) 838c2ecf20Sopenharmony_ci return; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci indev = skb->dev; 868c2ecf20Sopenharmony_ci skb->dev = to->dev; 878c2ecf20Sopenharmony_ci if (!local_orig) { 888c2ecf20Sopenharmony_ci if (skb_warn_if_lro(skb)) { 898c2ecf20Sopenharmony_ci kfree_skb(skb); 908c2ecf20Sopenharmony_ci return; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci br_hook = NF_BR_FORWARD; 938c2ecf20Sopenharmony_ci skb_forward_csum(skb); 948c2ecf20Sopenharmony_ci net = dev_net(indev); 958c2ecf20Sopenharmony_ci } else { 968c2ecf20Sopenharmony_ci if (unlikely(netpoll_tx_running(to->br->dev))) { 978c2ecf20Sopenharmony_ci skb_push(skb, ETH_HLEN); 988c2ecf20Sopenharmony_ci if (!is_skb_forwardable(skb->dev, skb)) 998c2ecf20Sopenharmony_ci kfree_skb(skb); 1008c2ecf20Sopenharmony_ci else 1018c2ecf20Sopenharmony_ci br_netpoll_send_skb(to, skb); 1028c2ecf20Sopenharmony_ci return; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci br_hook = NF_BR_LOCAL_OUT; 1058c2ecf20Sopenharmony_ci net = dev_net(skb->dev); 1068c2ecf20Sopenharmony_ci indev = NULL; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci NF_HOOK(NFPROTO_BRIDGE, br_hook, 1108c2ecf20Sopenharmony_ci net, NULL, skb, indev, skb->dev, 1118c2ecf20Sopenharmony_ci br_forward_finish); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int deliver_clone(const struct net_bridge_port *prev, 1158c2ecf20Sopenharmony_ci struct sk_buff *skb, bool local_orig) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci skb = skb_clone(skb, GFP_ATOMIC); 1208c2ecf20Sopenharmony_ci if (!skb) { 1218c2ecf20Sopenharmony_ci DEV_STATS_INC(dev, tx_dropped); 1228c2ecf20Sopenharmony_ci return -ENOMEM; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci __br_forward(prev, skb, local_orig); 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/** 1308c2ecf20Sopenharmony_ci * br_forward - forward a packet to a specific port 1318c2ecf20Sopenharmony_ci * @to: destination port 1328c2ecf20Sopenharmony_ci * @skb: packet being forwarded 1338c2ecf20Sopenharmony_ci * @local_rcv: packet will be received locally after forwarding 1348c2ecf20Sopenharmony_ci * @local_orig: packet is locally originated 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * Should be called with rcu_read_lock. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_civoid br_forward(const struct net_bridge_port *to, 1398c2ecf20Sopenharmony_ci struct sk_buff *skb, bool local_rcv, bool local_orig) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci if (unlikely(!to)) 1428c2ecf20Sopenharmony_ci goto out; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* redirect to backup link if the destination port is down */ 1458c2ecf20Sopenharmony_ci if (rcu_access_pointer(to->backup_port) && !netif_carrier_ok(to->dev)) { 1468c2ecf20Sopenharmony_ci struct net_bridge_port *backup_port; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci backup_port = rcu_dereference(to->backup_port); 1498c2ecf20Sopenharmony_ci if (unlikely(!backup_port)) 1508c2ecf20Sopenharmony_ci goto out; 1518c2ecf20Sopenharmony_ci to = backup_port; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (should_deliver(to, skb)) { 1558c2ecf20Sopenharmony_ci if (local_rcv) 1568c2ecf20Sopenharmony_ci deliver_clone(to, skb, local_orig); 1578c2ecf20Sopenharmony_ci else 1588c2ecf20Sopenharmony_ci __br_forward(to, skb, local_orig); 1598c2ecf20Sopenharmony_ci return; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ciout: 1638c2ecf20Sopenharmony_ci if (!local_rcv) 1648c2ecf20Sopenharmony_ci kfree_skb(skb); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(br_forward); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic struct net_bridge_port *maybe_deliver( 1698c2ecf20Sopenharmony_ci struct net_bridge_port *prev, struct net_bridge_port *p, 1708c2ecf20Sopenharmony_ci struct sk_buff *skb, bool local_orig) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci u8 igmp_type = br_multicast_igmp_type(skb); 1738c2ecf20Sopenharmony_ci int err; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (!should_deliver(p, skb)) 1768c2ecf20Sopenharmony_ci return prev; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (!prev) 1798c2ecf20Sopenharmony_ci goto out; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci err = deliver_clone(prev, skb, local_orig); 1828c2ecf20Sopenharmony_ci if (err) 1838c2ecf20Sopenharmony_ci return ERR_PTR(err); 1848c2ecf20Sopenharmony_ciout: 1858c2ecf20Sopenharmony_ci br_multicast_count(p->br, p, skb, igmp_type, BR_MCAST_DIR_TX); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return p; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* called under rcu_read_lock */ 1918c2ecf20Sopenharmony_civoid br_flood(struct net_bridge *br, struct sk_buff *skb, 1928c2ecf20Sopenharmony_ci enum br_pkt_type pkt_type, bool local_rcv, bool local_orig) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct net_bridge_port *prev = NULL; 1958c2ecf20Sopenharmony_ci struct net_bridge_port *p; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci list_for_each_entry_rcu(p, &br->port_list, list) { 1988c2ecf20Sopenharmony_ci /* Do not flood unicast traffic to ports that turn it off, nor 1998c2ecf20Sopenharmony_ci * other traffic if flood off, except for traffic we originate 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci switch (pkt_type) { 2028c2ecf20Sopenharmony_ci case BR_PKT_UNICAST: 2038c2ecf20Sopenharmony_ci if (!(p->flags & BR_FLOOD)) 2048c2ecf20Sopenharmony_ci continue; 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci case BR_PKT_MULTICAST: 2078c2ecf20Sopenharmony_ci if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev) 2088c2ecf20Sopenharmony_ci continue; 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci case BR_PKT_BROADCAST: 2118c2ecf20Sopenharmony_ci if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev) 2128c2ecf20Sopenharmony_ci continue; 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* Do not flood to ports that enable proxy ARP */ 2178c2ecf20Sopenharmony_ci if (p->flags & BR_PROXYARP) 2188c2ecf20Sopenharmony_ci continue; 2198c2ecf20Sopenharmony_ci if ((p->flags & (BR_PROXYARP_WIFI | BR_NEIGH_SUPPRESS)) && 2208c2ecf20Sopenharmony_ci BR_INPUT_SKB_CB(skb)->proxyarp_replied) 2218c2ecf20Sopenharmony_ci continue; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci prev = maybe_deliver(prev, p, skb, local_orig); 2248c2ecf20Sopenharmony_ci if (IS_ERR(prev)) 2258c2ecf20Sopenharmony_ci goto out; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (!prev) 2298c2ecf20Sopenharmony_ci goto out; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (local_rcv) 2328c2ecf20Sopenharmony_ci deliver_clone(prev, skb, local_orig); 2338c2ecf20Sopenharmony_ci else 2348c2ecf20Sopenharmony_ci __br_forward(prev, skb, local_orig); 2358c2ecf20Sopenharmony_ci return; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciout: 2388c2ecf20Sopenharmony_ci if (!local_rcv) 2398c2ecf20Sopenharmony_ci kfree_skb(skb); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci#ifdef CONFIG_BRIDGE_IGMP_SNOOPING 2438c2ecf20Sopenharmony_cistatic void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb, 2448c2ecf20Sopenharmony_ci const unsigned char *addr, bool local_orig) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; 2478c2ecf20Sopenharmony_ci const unsigned char *src = eth_hdr(skb)->h_source; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (!should_deliver(p, skb)) 2508c2ecf20Sopenharmony_ci return; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */ 2538c2ecf20Sopenharmony_ci if (skb->dev == p->dev && ether_addr_equal(src, addr)) 2548c2ecf20Sopenharmony_ci return; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci skb = skb_copy(skb, GFP_ATOMIC); 2578c2ecf20Sopenharmony_ci if (!skb) { 2588c2ecf20Sopenharmony_ci DEV_STATS_INC(dev, tx_dropped); 2598c2ecf20Sopenharmony_ci return; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (!is_broadcast_ether_addr(addr)) 2638c2ecf20Sopenharmony_ci memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci __br_forward(p, skb, local_orig); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* called with rcu_read_lock */ 2698c2ecf20Sopenharmony_civoid br_multicast_flood(struct net_bridge_mdb_entry *mdst, 2708c2ecf20Sopenharmony_ci struct sk_buff *skb, 2718c2ecf20Sopenharmony_ci bool local_rcv, bool local_orig) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; 2748c2ecf20Sopenharmony_ci struct net_bridge *br = netdev_priv(dev); 2758c2ecf20Sopenharmony_ci struct net_bridge_port *prev = NULL; 2768c2ecf20Sopenharmony_ci struct net_bridge_port_group *p; 2778c2ecf20Sopenharmony_ci bool allow_mode_include = true; 2788c2ecf20Sopenharmony_ci struct hlist_node *rp; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci rp = rcu_dereference(hlist_first_rcu(&br->router_list)); 2818c2ecf20Sopenharmony_ci if (mdst) { 2828c2ecf20Sopenharmony_ci p = rcu_dereference(mdst->ports); 2838c2ecf20Sopenharmony_ci if (br_multicast_should_handle_mode(br, mdst->addr.proto) && 2848c2ecf20Sopenharmony_ci br_multicast_is_star_g(&mdst->addr)) 2858c2ecf20Sopenharmony_ci allow_mode_include = false; 2868c2ecf20Sopenharmony_ci } else { 2878c2ecf20Sopenharmony_ci p = NULL; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci while (p || rp) { 2918c2ecf20Sopenharmony_ci struct net_bridge_port *port, *lport, *rport; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci lport = p ? p->key.port : NULL; 2948c2ecf20Sopenharmony_ci rport = hlist_entry_safe(rp, struct net_bridge_port, rlist); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if ((unsigned long)lport > (unsigned long)rport) { 2978c2ecf20Sopenharmony_ci port = lport; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (port->flags & BR_MULTICAST_TO_UNICAST) { 3008c2ecf20Sopenharmony_ci maybe_deliver_addr(lport, skb, p->eth_addr, 3018c2ecf20Sopenharmony_ci local_orig); 3028c2ecf20Sopenharmony_ci goto delivered; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci if ((!allow_mode_include && 3058c2ecf20Sopenharmony_ci p->filter_mode == MCAST_INCLUDE) || 3068c2ecf20Sopenharmony_ci (p->flags & MDB_PG_FLAGS_BLOCKED)) 3078c2ecf20Sopenharmony_ci goto delivered; 3088c2ecf20Sopenharmony_ci } else { 3098c2ecf20Sopenharmony_ci port = rport; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci prev = maybe_deliver(prev, port, skb, local_orig); 3138c2ecf20Sopenharmony_ci if (IS_ERR(prev)) 3148c2ecf20Sopenharmony_ci goto out; 3158c2ecf20Sopenharmony_cidelivered: 3168c2ecf20Sopenharmony_ci if ((unsigned long)lport >= (unsigned long)port) 3178c2ecf20Sopenharmony_ci p = rcu_dereference(p->next); 3188c2ecf20Sopenharmony_ci if ((unsigned long)rport >= (unsigned long)port) 3198c2ecf20Sopenharmony_ci rp = rcu_dereference(hlist_next_rcu(rp)); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (!prev) 3238c2ecf20Sopenharmony_ci goto out; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (local_rcv) 3268c2ecf20Sopenharmony_ci deliver_clone(prev, skb, local_orig); 3278c2ecf20Sopenharmony_ci else 3288c2ecf20Sopenharmony_ci __br_forward(prev, skb, local_orig); 3298c2ecf20Sopenharmony_ci return; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ciout: 3328c2ecf20Sopenharmony_ci if (!local_rcv) 3338c2ecf20Sopenharmony_ci kfree_skb(skb); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci#endif 336