~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/dsa/tag.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * DSA tagging protocol handling
  4  *
  5  * Copyright (c) 2008-2009 Marvell Semiconductor
  6  * Copyright (c) 2013 Florian Fainelli <florian@openwrt.org>
  7  * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
  8  */
  9 
 10 #include <linux/netdevice.h>
 11 #include <linux/ptp_classify.h>
 12 #include <linux/skbuff.h>
 13 #include <net/dsa.h>
 14 #include <net/dst_metadata.h>
 15 
 16 #include "tag.h"
 17 #include "user.h"
 18 
 19 static LIST_HEAD(dsa_tag_drivers_list);
 20 static DEFINE_MUTEX(dsa_tag_drivers_lock);
 21 
 22 /* Determine if we should defer delivery of skb until we have a rx timestamp.
 23  *
 24  * Called from dsa_switch_rcv. For now, this will only work if tagging is
 25  * enabled on the switch. Normally the MAC driver would retrieve the hardware
 26  * timestamp when it reads the packet out of the hardware. However in a DSA
 27  * switch, the DSA driver owning the interface to which the packet is
 28  * delivered is never notified unless we do so here.
 29  */
 30 static bool dsa_skb_defer_rx_timestamp(struct dsa_user_priv *p,
 31                                        struct sk_buff *skb)
 32 {
 33         struct dsa_switch *ds = p->dp->ds;
 34         unsigned int type;
 35 
 36         if (!ds->ops->port_rxtstamp)
 37                 return false;
 38 
 39         if (skb_headroom(skb) < ETH_HLEN)
 40                 return false;
 41 
 42         __skb_push(skb, ETH_HLEN);
 43 
 44         type = ptp_classify_raw(skb);
 45 
 46         __skb_pull(skb, ETH_HLEN);
 47 
 48         if (type == PTP_CLASS_NONE)
 49                 return false;
 50 
 51         return ds->ops->port_rxtstamp(ds, p->dp->index, skb, type);
 52 }
 53 
 54 static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
 55                           struct packet_type *pt, struct net_device *unused)
 56 {
 57         struct metadata_dst *md_dst = skb_metadata_dst(skb);
 58         struct dsa_port *cpu_dp = dev->dsa_ptr;
 59         struct sk_buff *nskb = NULL;
 60         struct dsa_user_priv *p;
 61 
 62         if (unlikely(!cpu_dp)) {
 63                 kfree_skb(skb);
 64                 return 0;
 65         }
 66 
 67         skb = skb_unshare(skb, GFP_ATOMIC);
 68         if (!skb)
 69                 return 0;
 70 
 71         if (md_dst && md_dst->type == METADATA_HW_PORT_MUX) {
 72                 unsigned int port = md_dst->u.port_info.port_id;
 73 
 74                 skb_dst_drop(skb);
 75                 if (!skb_has_extensions(skb))
 76                         skb->slow_gro = 0;
 77 
 78                 skb->dev = dsa_conduit_find_user(dev, 0, port);
 79                 if (likely(skb->dev)) {
 80                         dsa_default_offload_fwd_mark(skb);
 81                         nskb = skb;
 82                 }
 83         } else {
 84                 nskb = cpu_dp->rcv(skb, dev);
 85         }
 86 
 87         if (!nskb) {
 88                 kfree_skb(skb);
 89                 return 0;
 90         }
 91 
 92         skb = nskb;
 93         skb_push(skb, ETH_HLEN);
 94         skb->pkt_type = PACKET_HOST;
 95         skb->protocol = eth_type_trans(skb, skb->dev);
 96 
 97         if (unlikely(!dsa_user_dev_check(skb->dev))) {
 98                 /* Packet is to be injected directly on an upper
 99                  * device, e.g. a team/bond, so skip all DSA-port
100                  * specific actions.
101                  */
102                 netif_rx(skb);
103                 return 0;
104         }
105 
106         p = netdev_priv(skb->dev);
107 
108         if (unlikely(cpu_dp->ds->untag_bridge_pvid ||
109                      cpu_dp->ds->untag_vlan_aware_bridge_pvid)) {
110                 nskb = dsa_software_vlan_untag(skb);
111                 if (!nskb) {
112                         kfree_skb(skb);
113                         return 0;
114                 }
115                 skb = nskb;
116         }
117 
118         dev_sw_netstats_rx_add(skb->dev, skb->len + ETH_HLEN);
119 
120         if (dsa_skb_defer_rx_timestamp(p, skb))
121                 return 0;
122 
123         gro_cells_receive(&p->gcells, skb);
124 
125         return 0;
126 }
127 
128 struct packet_type dsa_pack_type __read_mostly = {
129         .type   = cpu_to_be16(ETH_P_XDSA),
130         .func   = dsa_switch_rcv,
131 };
132 
133 static void dsa_tag_driver_register(struct dsa_tag_driver *dsa_tag_driver,
134                                     struct module *owner)
135 {
136         dsa_tag_driver->owner = owner;
137 
138         mutex_lock(&dsa_tag_drivers_lock);
139         list_add_tail(&dsa_tag_driver->list, &dsa_tag_drivers_list);
140         mutex_unlock(&dsa_tag_drivers_lock);
141 }
142 
143 void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[],
144                               unsigned int count, struct module *owner)
145 {
146         unsigned int i;
147 
148         for (i = 0; i < count; i++)
149                 dsa_tag_driver_register(dsa_tag_driver_array[i], owner);
150 }
151 
152 static void dsa_tag_driver_unregister(struct dsa_tag_driver *dsa_tag_driver)
153 {
154         mutex_lock(&dsa_tag_drivers_lock);
155         list_del(&dsa_tag_driver->list);
156         mutex_unlock(&dsa_tag_drivers_lock);
157 }
158 EXPORT_SYMBOL_GPL(dsa_tag_drivers_register);
159 
160 void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[],
161                                 unsigned int count)
162 {
163         unsigned int i;
164 
165         for (i = 0; i < count; i++)
166                 dsa_tag_driver_unregister(dsa_tag_driver_array[i]);
167 }
168 EXPORT_SYMBOL_GPL(dsa_tag_drivers_unregister);
169 
170 const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops)
171 {
172         return ops->name;
173 };
174 
175 /* Function takes a reference on the module owning the tagger,
176  * so dsa_tag_driver_put must be called afterwards.
177  */
178 const struct dsa_device_ops *dsa_tag_driver_get_by_name(const char *name)
179 {
180         const struct dsa_device_ops *ops = ERR_PTR(-ENOPROTOOPT);
181         struct dsa_tag_driver *dsa_tag_driver;
182 
183         request_module("%s%s", DSA_TAG_DRIVER_ALIAS, name);
184 
185         mutex_lock(&dsa_tag_drivers_lock);
186         list_for_each_entry(dsa_tag_driver, &dsa_tag_drivers_list, list) {
187                 const struct dsa_device_ops *tmp = dsa_tag_driver->ops;
188 
189                 if (strcmp(name, tmp->name))
190                         continue;
191 
192                 if (!try_module_get(dsa_tag_driver->owner))
193                         break;
194 
195                 ops = tmp;
196                 break;
197         }
198         mutex_unlock(&dsa_tag_drivers_lock);
199 
200         return ops;
201 }
202 
203 const struct dsa_device_ops *dsa_tag_driver_get_by_id(int tag_protocol)
204 {
205         struct dsa_tag_driver *dsa_tag_driver;
206         const struct dsa_device_ops *ops;
207         bool found = false;
208 
209         request_module("%sid-%d", DSA_TAG_DRIVER_ALIAS, tag_protocol);
210 
211         mutex_lock(&dsa_tag_drivers_lock);
212         list_for_each_entry(dsa_tag_driver, &dsa_tag_drivers_list, list) {
213                 ops = dsa_tag_driver->ops;
214                 if (ops->proto == tag_protocol) {
215                         found = true;
216                         break;
217                 }
218         }
219 
220         if (found) {
221                 if (!try_module_get(dsa_tag_driver->owner))
222                         ops = ERR_PTR(-ENOPROTOOPT);
223         } else {
224                 ops = ERR_PTR(-ENOPROTOOPT);
225         }
226 
227         mutex_unlock(&dsa_tag_drivers_lock);
228 
229         return ops;
230 }
231 
232 void dsa_tag_driver_put(const struct dsa_device_ops *ops)
233 {
234         struct dsa_tag_driver *dsa_tag_driver;
235 
236         mutex_lock(&dsa_tag_drivers_lock);
237         list_for_each_entry(dsa_tag_driver, &dsa_tag_drivers_list, list) {
238                 if (dsa_tag_driver->ops == ops) {
239                         module_put(dsa_tag_driver->owner);
240                         break;
241                 }
242         }
243         mutex_unlock(&dsa_tag_drivers_lock);
244 }
245 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php