root/net/bridge/br_switchdev.c

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

DEFINITIONS

This source file includes following definitions.
  1. br_switchdev_mark_get
  2. nbp_switchdev_mark_set
  3. nbp_switchdev_frame_mark
  4. nbp_switchdev_allowed_egress
  5. br_switchdev_set_port_flag
  6. br_switchdev_fdb_call_notifiers
  7. br_switchdev_fdb_notify
  8. br_switchdev_port_vlan_add
  9. br_switchdev_port_vlan_del

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/kernel.h>
   3 #include <linux/list.h>
   4 #include <linux/netdevice.h>
   5 #include <linux/rtnetlink.h>
   6 #include <linux/skbuff.h>
   7 #include <net/switchdev.h>
   8 
   9 #include "br_private.h"
  10 
  11 static int br_switchdev_mark_get(struct net_bridge *br, struct net_device *dev)
  12 {
  13         struct net_bridge_port *p;
  14 
  15         /* dev is yet to be added to the port list. */
  16         list_for_each_entry(p, &br->port_list, list) {
  17                 if (netdev_port_same_parent_id(dev, p->dev))
  18                         return p->offload_fwd_mark;
  19         }
  20 
  21         return ++br->offload_fwd_mark;
  22 }
  23 
  24 int nbp_switchdev_mark_set(struct net_bridge_port *p)
  25 {
  26         struct netdev_phys_item_id ppid = { };
  27         int err;
  28 
  29         ASSERT_RTNL();
  30 
  31         err = dev_get_port_parent_id(p->dev, &ppid, true);
  32         if (err) {
  33                 if (err == -EOPNOTSUPP)
  34                         return 0;
  35                 return err;
  36         }
  37 
  38         p->offload_fwd_mark = br_switchdev_mark_get(p->br, p->dev);
  39 
  40         return 0;
  41 }
  42 
  43 void nbp_switchdev_frame_mark(const struct net_bridge_port *p,
  44                               struct sk_buff *skb)
  45 {
  46         if (skb->offload_fwd_mark && !WARN_ON_ONCE(!p->offload_fwd_mark))
  47                 BR_INPUT_SKB_CB(skb)->offload_fwd_mark = p->offload_fwd_mark;
  48 }
  49 
  50 bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p,
  51                                   const struct sk_buff *skb)
  52 {
  53         return !skb->offload_fwd_mark ||
  54                BR_INPUT_SKB_CB(skb)->offload_fwd_mark != p->offload_fwd_mark;
  55 }
  56 
  57 /* Flags that can be offloaded to hardware */
  58 #define BR_PORT_FLAGS_HW_OFFLOAD (BR_LEARNING | BR_FLOOD | \
  59                                   BR_MCAST_FLOOD | BR_BCAST_FLOOD)
  60 
  61 int br_switchdev_set_port_flag(struct net_bridge_port *p,
  62                                unsigned long flags,
  63                                unsigned long mask)
  64 {
  65         struct switchdev_attr attr = {
  66                 .orig_dev = p->dev,
  67                 .id = SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS,
  68                 .u.brport_flags = mask,
  69         };
  70         struct switchdev_notifier_port_attr_info info = {
  71                 .attr = &attr,
  72         };
  73         int err;
  74 
  75         if (mask & ~BR_PORT_FLAGS_HW_OFFLOAD)
  76                 return 0;
  77 
  78         /* We run from atomic context here */
  79         err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev,
  80                                        &info.info, NULL);
  81         err = notifier_to_errno(err);
  82         if (err == -EOPNOTSUPP)
  83                 return 0;
  84 
  85         if (err) {
  86                 br_warn(p->br, "bridge flag offload is not supported %u(%s)\n",
  87                         (unsigned int)p->port_no, p->dev->name);
  88                 return -EOPNOTSUPP;
  89         }
  90 
  91         attr.id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS;
  92         attr.flags = SWITCHDEV_F_DEFER;
  93         attr.u.brport_flags = flags;
  94 
  95         err = switchdev_port_attr_set(p->dev, &attr);
  96         if (err) {
  97                 br_warn(p->br, "error setting offload flag on port %u(%s)\n",
  98                         (unsigned int)p->port_no, p->dev->name);
  99                 return err;
 100         }
 101 
 102         return 0;
 103 }
 104 
 105 static void
 106 br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac,
 107                                 u16 vid, struct net_device *dev,
 108                                 bool added_by_user, bool offloaded)
 109 {
 110         struct switchdev_notifier_fdb_info info;
 111         unsigned long notifier_type;
 112 
 113         info.addr = mac;
 114         info.vid = vid;
 115         info.added_by_user = added_by_user;
 116         info.offloaded = offloaded;
 117         notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_DEVICE : SWITCHDEV_FDB_DEL_TO_DEVICE;
 118         call_switchdev_notifiers(notifier_type, dev, &info.info, NULL);
 119 }
 120 
 121 void
 122 br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
 123 {
 124         if (!fdb->dst)
 125                 return;
 126 
 127         switch (type) {
 128         case RTM_DELNEIGH:
 129                 br_switchdev_fdb_call_notifiers(false, fdb->key.addr.addr,
 130                                                 fdb->key.vlan_id,
 131                                                 fdb->dst->dev,
 132                                                 fdb->added_by_user,
 133                                                 fdb->offloaded);
 134                 break;
 135         case RTM_NEWNEIGH:
 136                 br_switchdev_fdb_call_notifiers(true, fdb->key.addr.addr,
 137                                                 fdb->key.vlan_id,
 138                                                 fdb->dst->dev,
 139                                                 fdb->added_by_user,
 140                                                 fdb->offloaded);
 141                 break;
 142         }
 143 }
 144 
 145 int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
 146                                struct netlink_ext_ack *extack)
 147 {
 148         struct switchdev_obj_port_vlan v = {
 149                 .obj.orig_dev = dev,
 150                 .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
 151                 .flags = flags,
 152                 .vid_begin = vid,
 153                 .vid_end = vid,
 154         };
 155 
 156         return switchdev_port_obj_add(dev, &v.obj, extack);
 157 }
 158 
 159 int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid)
 160 {
 161         struct switchdev_obj_port_vlan v = {
 162                 .obj.orig_dev = dev,
 163                 .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
 164                 .vid_begin = vid,
 165                 .vid_end = vid,
 166         };
 167 
 168         return switchdev_port_obj_del(dev, &v.obj);
 169 }

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