Commit 090096bf3db1c281ddd034573260045888a68fea

Authored by Vlad Yasevich
Committed by David S. Miller
1 parent 6906f4ed6f

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