Commit 090096bf3db1c281ddd034573260045888a68fea
Committed by
David S. Miller
1 parent
6906f4ed6f
Exists in
master
and in
20 other branches
net: generic fdb support for drivers without ndo_fdb_<op>
If the driver does not support the ndo_op use the generic handler for it. This should work in the majority of cases. Eventually the fdb_dflt_add call gets translated into a __dev_set_rx_mode() call which should handle hardware support for filtering via the IFF_UNICAST_FLT flag. Namely IFF_UNICAST_FLT indicates if the hardware can do unicast address filtering. If no support is available the device is put into promisc mode. Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> Signed-off-by: John Fastabend <john.r.fastabend@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 2 changed files with 84 additions and 6 deletions Side-by-side Diff
include/linux/rtnetlink.h
... | ... | @@ -69,6 +69,15 @@ |
69 | 69 | struct netlink_callback *cb, |
70 | 70 | struct net_device *dev, |
71 | 71 | int idx); |
72 | +extern int ndo_dflt_fdb_add(struct ndmsg *ndm, | |
73 | + struct nlattr *tb[], | |
74 | + struct net_device *dev, | |
75 | + const unsigned char *addr, | |
76 | + u16 flags); | |
77 | +extern int ndo_dflt_fdb_del(struct ndmsg *ndm, | |
78 | + struct nlattr *tb[], | |
79 | + struct net_device *dev, | |
80 | + const unsigned char *addr); | |
72 | 81 | |
73 | 82 | extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, |
74 | 83 | struct net_device *dev, u16 mode); |
net/core/rtnetlink.c
... | ... | @@ -2048,6 +2048,38 @@ |
2048 | 2048 | rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); |
2049 | 2049 | } |
2050 | 2050 | |
2051 | +/** | |
2052 | + * ndo_dflt_fdb_add - default netdevice operation to add an FDB entry | |
2053 | + */ | |
2054 | +int ndo_dflt_fdb_add(struct ndmsg *ndm, | |
2055 | + struct nlattr *tb[], | |
2056 | + struct net_device *dev, | |
2057 | + const unsigned char *addr, | |
2058 | + u16 flags) | |
2059 | +{ | |
2060 | + int err = -EINVAL; | |
2061 | + | |
2062 | + /* If aging addresses are supported device will need to | |
2063 | + * implement its own handler for this. | |
2064 | + */ | |
2065 | + if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) { | |
2066 | + pr_info("%s: FDB only supports static addresses\n", dev->name); | |
2067 | + return err; | |
2068 | + } | |
2069 | + | |
2070 | + if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) | |
2071 | + err = dev_uc_add_excl(dev, addr); | |
2072 | + else if (is_multicast_ether_addr(addr)) | |
2073 | + err = dev_mc_add_excl(dev, addr); | |
2074 | + | |
2075 | + /* Only return duplicate errors if NLM_F_EXCL is set */ | |
2076 | + if (err == -EEXIST && !(flags & NLM_F_EXCL)) | |
2077 | + err = 0; | |
2078 | + | |
2079 | + return err; | |
2080 | +} | |
2081 | +EXPORT_SYMBOL(ndo_dflt_fdb_add); | |
2082 | + | |
2051 | 2083 | static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
2052 | 2084 | { |
2053 | 2085 | struct net *net = sock_net(skb->sk); |
... | ... | @@ -2100,10 +2132,13 @@ |
2100 | 2132 | } |
2101 | 2133 | |
2102 | 2134 | /* Embedded bridge, macvlan, and any other device support */ |
2103 | - if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_add) { | |
2104 | - err = dev->netdev_ops->ndo_fdb_add(ndm, tb, | |
2105 | - dev, addr, | |
2106 | - nlh->nlmsg_flags); | |
2135 | + if ((ndm->ndm_flags & NTF_SELF)) { | |
2136 | + if (dev->netdev_ops->ndo_fdb_add) | |
2137 | + err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr, | |
2138 | + nlh->nlmsg_flags); | |
2139 | + else | |
2140 | + err = ndo_dflt_fdb_add(ndm, tb, dev, addr, | |
2141 | + nlh->nlmsg_flags); | |
2107 | 2142 | |
2108 | 2143 | if (!err) { |
2109 | 2144 | rtnl_fdb_notify(dev, addr, RTM_NEWNEIGH); |
... | ... | @@ -2114,6 +2149,35 @@ |
2114 | 2149 | return err; |
2115 | 2150 | } |
2116 | 2151 | |
2152 | +/** | |
2153 | + * ndo_dflt_fdb_del - default netdevice operation to delete an FDB entry | |
2154 | + */ | |
2155 | +int ndo_dflt_fdb_del(struct ndmsg *ndm, | |
2156 | + struct nlattr *tb[], | |
2157 | + struct net_device *dev, | |
2158 | + const unsigned char *addr) | |
2159 | +{ | |
2160 | + int err = -EOPNOTSUPP; | |
2161 | + | |
2162 | + /* If aging addresses are supported device will need to | |
2163 | + * implement its own handler for this. | |
2164 | + */ | |
2165 | + if (ndm->ndm_state & NUD_PERMANENT) { | |
2166 | + pr_info("%s: FDB only supports static addresses\n", dev->name); | |
2167 | + return -EINVAL; | |
2168 | + } | |
2169 | + | |
2170 | + if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) | |
2171 | + err = dev_uc_del(dev, addr); | |
2172 | + else if (is_multicast_ether_addr(addr)) | |
2173 | + err = dev_mc_del(dev, addr); | |
2174 | + else | |
2175 | + err = -EINVAL; | |
2176 | + | |
2177 | + return err; | |
2178 | +} | |
2179 | +EXPORT_SYMBOL(ndo_dflt_fdb_del); | |
2180 | + | |
2117 | 2181 | static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
2118 | 2182 | { |
2119 | 2183 | struct net *net = sock_net(skb->sk); |
... | ... | @@ -2171,8 +2235,11 @@ |
2171 | 2235 | } |
2172 | 2236 | |
2173 | 2237 | /* Embedded bridge, macvlan, and any other device support */ |
2174 | - if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) { | |
2175 | - err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr); | |
2238 | + if (ndm->ndm_flags & NTF_SELF) { | |
2239 | + if (dev->netdev_ops->ndo_fdb_del) | |
2240 | + err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr); | |
2241 | + else | |
2242 | + err = ndo_dflt_fdb_del(ndm, tb, dev, addr); | |
2176 | 2243 | |
2177 | 2244 | if (!err) { |
2178 | 2245 | rtnl_fdb_notify(dev, addr, RTM_DELNEIGH); |
... | ... | @@ -2257,6 +2324,8 @@ |
2257 | 2324 | |
2258 | 2325 | if (dev->netdev_ops->ndo_fdb_dump) |
2259 | 2326 | idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx); |
2327 | + else | |
2328 | + ndo_dflt_fdb_dump(skb, cb, dev, idx); | |
2260 | 2329 | } |
2261 | 2330 | rcu_read_unlock(); |
2262 | 2331 |