History

net: dsa: report and change port default priority using dcbnl

The port-based default QoS class is assigned to packets that lack a VLAN PCP (or the port is configured to not trust the VLAN PCP), an IP DSCP (or the port is configured to not trust IP DSCP), and packets on which no tc-skbedit action has matched. Similar to other drivers, this can be exposed to user space using the DCB Application Priority Table. IEEE 802.1Q-2018 specifies in Table D-8 - Sel field values that when the Selector is 1, the Protocol ID value of 0 denotes the "Default application priority. For use when application priority is not otherwise specified." The way in which the dcbnl integration in DSA has been designed has to do with its requirements. Andrew Lunn explains that SOHO switches are expected to come with some sort of pre-configured QoS profile, and that it is desirable for this to come pre-loaded into the DSA slave interfaces' DCB application priority table. In the dcbnl design, this is possible because calls to dcb_ieee_setapp() can be initiated by anyone including being self-initiated by this device driver. However, what makes this challenging to implement in DSA is that the DSA core manages the net_devices (effectively hiding them from drivers), while drivers manage the hardware. The DSA core has no knowledge of what individual drivers' QoS policies are. DSA could export to drivers a wrapper over dcb_ieee_setapp() and these could call that function to pre-populate the app priority table, however drivers don't have a good moment in time to do this. The dsa_switch_ops :: setup() method gets called before the net_devices are created (dsa_slave_create), and so is dsa_switch_ops :: port_setup(). What remains is dsa_switch_ops :: port_enable(), but this gets called upon each ndo_open. If we add app table entries on every open, we'd need to remove them on close, to avoid duplicate entry errors. But if we delete app priority entries on close, what we delete may not be the initial, driver pre-populated entries, but rather user-added entries. So it is clear that letting drivers choose the timing of the dcb_ieee_setapp() call is inappropriate. The alternative which was chosen is to introduce hardware-specific ops in dsa_switch_ops, and effectively hide dcbnl details from drivers as well. For pre-populating the application table, dsa_slave_dcbnl_init() will call ds->ops->port_get_default_prio() which is supposed to read from hardware. If the operation succeeds, DSA creates a default-prio app table entry. The method is called as soon as the slave_dev is registered, but before we release the rtnl_mutex. This is done such that user space sees the app table entries as soon as it sees the interface being registered. The fact that we populate slave_dev->dcbnl_ops with a non-NULL pointer changes behavior in dcb_doit() from net/dcb/dcbnl.c, which used to return -EOPNOTSUPP for any dcbnl operation where netdev->dcbnl_ops is NULL. Because there are still dcbnl-unaware DSA drivers even if they have dcbnl_ops populated, the way to restore the behavior is to make all dcbnl_ops return -EOPNOTSUPP on absence of the hardware-specific dsa_switch_ops method. The dcbnl framework absurdly allows there to be more than one app table entry for the same selector and protocol (in other words, more than one port-based default priority). In the iproute2 dcb program, there is a "replace" syntactical sugar command which performs an "add" and a "del" to hide this away. But we choose the largest configured priority when we call ds->ops->port_set_default_prio(), using __fls(). When there is no default-prio app table entry left, the port-default priority is restored to 0.

Vladimir Oltean committed 4 years ago

Commit d538eca1 parent 102e4a82 files · +144 −0Browse files

Unified · Split

2 files
  1. include/net/dsa.h +7 −0
  2. net/dsa/slave.c +137 −0
include/net/dsa.h+7−0
@@ -892,6 +892,13 @@ struct dsa_switch_ops { · 891 unmodified lines
892 int (*get_ts_info)(struct dsa_switch *ds, int port,892 int (*get_ts_info)(struct dsa_switch *ds, int port,
893 struct ethtool_ts_info *ts);893 struct ethtool_ts_info *ts);
894 894
895 /*
896 * DCB ops
897 */
898 int (*port_get_default_prio)(struct dsa_switch *ds, int port);
899 int (*port_set_default_prio)(struct dsa_switch *ds, int port,
900 u8 prio);
901
895 /*902 /*
896 * Suspend and resume903 * Suspend and resume
897 */904 */
net/dsa/slave.c+137−0
@@ -19,6 +19,7 @@ · 18 unmodified lines
19#include <net/tc_act/tc_mirred.h>19#include <net/tc_act/tc_mirred.h>
20#include <linux/if_bridge.h>20#include <linux/if_bridge.h>
21#include <linux/if_hsr.h>21#include <linux/if_hsr.h>
22#include <net/dcbnl.h>
22#include <linux/netpoll.h>23#include <linux/netpoll.h>
23 24
24#include "dsa_priv.h"25#include "dsa_priv.h"
@@ -1852,6 +1853,123 @@ out_master_failed: · 1827 unmodified lines
1852 return err;1853 return err;
1853}1854}
1854 1855
1856static int __maybe_unused
1857dsa_slave_dcbnl_set_default_prio(struct net_device *dev, struct dcb_app *app)
1858{
1859 struct dsa_port *dp = dsa_slave_to_port(dev);
1860 struct dsa_switch *ds = dp->ds;
1861 unsigned long mask, new_prio;
1862 int err, port = dp->index;
1863
1864 if (!ds->ops->port_set_default_prio)
1865 return -EOPNOTSUPP;
1866
1867 err = dcb_ieee_setapp(dev, app);
1868 if (err)
1869 return err;
1870
1871 mask = dcb_ieee_getapp_mask(dev, app);
1872 new_prio = __fls(mask);
1873
1874 err = ds->ops->port_set_default_prio(ds, port, new_prio);
1875 if (err) {
1876 dcb_ieee_delapp(dev, app);
1877 return err;
1878 }
1879
1880 return 0;
1881}
1882
1883static int __maybe_unused dsa_slave_dcbnl_ieee_setapp(struct net_device *dev,
1884 struct dcb_app *app)
1885{
1886 switch (app->selector) {
1887 case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
1888 switch (app->protocol) {
1889 case 0:
1890 return dsa_slave_dcbnl_set_default_prio(dev, app);
1891 default:
1892 return -EOPNOTSUPP;
1893 }
1894 break;
1895 default:
1896 return -EOPNOTSUPP;
1897 }
1898}
1899
1900static int __maybe_unused
1901dsa_slave_dcbnl_del_default_prio(struct net_device *dev, struct dcb_app *app)
1902{
1903 struct dsa_port *dp = dsa_slave_to_port(dev);
1904 struct dsa_switch *ds = dp->ds;
1905 unsigned long mask, new_prio;
1906 int err, port = dp->index;
1907
1908 if (!ds->ops->port_set_default_prio)
1909 return -EOPNOTSUPP;
1910
1911 err = dcb_ieee_delapp(dev, app);
1912 if (err)
1913 return err;
1914
1915 mask = dcb_ieee_getapp_mask(dev, app);
1916 new_prio = mask ? __fls(mask) : 0;
1917
1918 err = ds->ops->port_set_default_prio(ds, port, new_prio);
1919 if (err) {
1920 dcb_ieee_setapp(dev, app);
1921 return err;
1922 }
1923
1924 return 0;
1925}
1926
1927static int __maybe_unused dsa_slave_dcbnl_ieee_delapp(struct net_device *dev,
1928 struct dcb_app *app)
1929{
1930 switch (app->selector) {
1931 case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
1932 switch (app->protocol) {
1933 case 0:
1934 return dsa_slave_dcbnl_del_default_prio(dev, app);
1935 default:
1936 return -EOPNOTSUPP;
1937 }
1938 break;
1939 default:
1940 return -EOPNOTSUPP;
1941 }
1942}
1943
1944/* Pre-populate the DCB application priority table with the priorities
1945 * configured during switch setup, which we read from hardware here.
1946 */
1947static int dsa_slave_dcbnl_init(struct net_device *dev)
1948{
1949 struct dsa_port *dp = dsa_slave_to_port(dev);
1950 struct dsa_switch *ds = dp->ds;
1951 int port = dp->index;
1952 int err;
1953
1954 if (ds->ops->port_get_default_prio) {
1955 int prio = ds->ops->port_get_default_prio(ds, port);
1956 struct dcb_app app = {
1957 .selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE,
1958 .protocol = 0,
1959 .priority = prio,
1960 };
1961
1962 if (prio < 0)
1963 return prio;
1964
1965 err = dcb_ieee_setapp(dev, &app);
1966 if (err)
1967 return err;
1968 }
1969
1970 return 0;
1971}
1972
1855static const struct ethtool_ops dsa_slave_ethtool_ops = {1973static const struct ethtool_ops dsa_slave_ethtool_ops = {
1856 .get_drvinfo = dsa_slave_get_drvinfo,1974 .get_drvinfo = dsa_slave_get_drvinfo,
1857 .get_regs_len = dsa_slave_get_regs_len,1975 .get_regs_len = dsa_slave_get_regs_len,
@@ -1881,6 +1999,11 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = { · 23 unmodified lines
1881 .self_test = dsa_slave_net_selftest,1999 .self_test = dsa_slave_net_selftest,
1882};2000};
1883 2001
2002static const struct dcbnl_rtnl_ops __maybe_unused dsa_slave_dcbnl_ops = {
2003 .ieee_setapp = dsa_slave_dcbnl_ieee_setapp,
2004 .ieee_delapp = dsa_slave_dcbnl_ieee_delapp,
2005};
2006
1884static struct devlink_port *dsa_slave_get_devlink_port(struct net_device *dev)2007static struct devlink_port *dsa_slave_get_devlink_port(struct net_device *dev)
1885{2008{
1886 struct dsa_port *dp = dsa_slave_to_port(dev);2009 struct dsa_port *dp = dsa_slave_to_port(dev);
@@ -2105,6 +2228,9 @@ int dsa_slave_create(struct dsa_port *port) · 218 unmodified lines
2105 return -ENOMEM;2228 return -ENOMEM;
2106 2229
2107 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;2230 slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
2231#if IS_ENABLED(CONFIG_DCB)
2232 slave_dev->dcbnl_ops = &dsa_slave_dcbnl_ops;
2233#endif
2108 if (!is_zero_ether_addr(port->mac))2234 if (!is_zero_ether_addr(port->mac))
2109 eth_hw_addr_set(slave_dev, port->mac);2235 eth_hw_addr_set(slave_dev, port->mac);
2110 else2236 else
@@ -2162,6 +2288,17 @@ int dsa_slave_create(struct dsa_port *port) · 51 unmodified lines
2162 goto out_phy;2288 goto out_phy;
2163 }2289 }
2164 2290
2291 if (IS_ENABLED(CONFIG_DCB)) {
2292 ret = dsa_slave_dcbnl_init(slave_dev);
2293 if (ret) {
2294 netdev_err(slave_dev,
2295 "failed to initialize DCB: %pe\n",
2296 ERR_PTR(ret));
2297 rtnl_unlock();
2298 goto out_unregister;
2299 }
2300 }
2301
2165 ret = netdev_upper_dev_link(master, slave_dev, NULL);2302 ret = netdev_upper_dev_link(master, slave_dev, NULL);
2166 2303
2167 rtnl_unlock();2304 rtnl_unlock();

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t