aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevic@redhat.com>2013-03-06 10:39:42 -0500
committerDavid S. Miller <davem@davemloft.net>2013-03-07 15:29:45 -0500
commit090096bf3db1c281ddd034573260045888a68fea (patch)
treeabadf4a4ebdc4177ac59c32818fc73a9ba2a492b /net
parent6906f4ed6f85b2d72fd944e15da6a905fdde8b40 (diff)
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>
Diffstat (limited to 'net')
-rw-r--r--net/core/rtnetlink.c81
1 files changed, 75 insertions, 6 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index b376410ff259..f95b6fbc29e9 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2048,6 +2048,38 @@ errout:
2048 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); 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 */
2054int 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}
2081EXPORT_SYMBOL(ndo_dflt_fdb_add);
2082
2051static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 2083static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2052{ 2084{
2053 struct net *net = sock_net(skb->sk); 2085 struct net *net = sock_net(skb->sk);
@@ -2100,10 +2132,13 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2100 } 2132 }
2101 2133
2102 /* Embedded bridge, macvlan, and any other device support */ 2134 /* Embedded bridge, macvlan, and any other device support */
2103 if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_add) { 2135 if ((ndm->ndm_flags & NTF_SELF)) {
2104 err = dev->netdev_ops->ndo_fdb_add(ndm, tb, 2136 if (dev->netdev_ops->ndo_fdb_add)
2105 dev, addr, 2137 err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr,
2106 nlh->nlmsg_flags); 2138 nlh->nlmsg_flags);
2139 else
2140 err = ndo_dflt_fdb_add(ndm, tb, dev, addr,
2141 nlh->nlmsg_flags);
2107 2142
2108 if (!err) { 2143 if (!err) {
2109 rtnl_fdb_notify(dev, addr, RTM_NEWNEIGH); 2144 rtnl_fdb_notify(dev, addr, RTM_NEWNEIGH);
@@ -2114,6 +2149,35 @@ out:
2114 return err; 2149 return err;
2115} 2150}
2116 2151
2152/**
2153 * ndo_dflt_fdb_del - default netdevice operation to delete an FDB entry
2154 */
2155int 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}
2179EXPORT_SYMBOL(ndo_dflt_fdb_del);
2180
2117static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 2181static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2118{ 2182{
2119 struct net *net = sock_net(skb->sk); 2183 struct net *net = sock_net(skb->sk);
@@ -2171,8 +2235,11 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
2171 } 2235 }
2172 2236
2173 /* Embedded bridge, macvlan, and any other device support */ 2237 /* Embedded bridge, macvlan, and any other device support */
2174 if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) { 2238 if (ndm->ndm_flags & NTF_SELF) {
2175 err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr); 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 if (!err) { 2244 if (!err) {
2178 rtnl_fdb_notify(dev, addr, RTM_DELNEIGH); 2245 rtnl_fdb_notify(dev, addr, RTM_DELNEIGH);
@@ -2257,6 +2324,8 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
2257 2324
2258 if (dev->netdev_ops->ndo_fdb_dump) 2325 if (dev->netdev_ops->ndo_fdb_dump)
2259 idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx); 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 rcu_read_unlock(); 2330 rcu_read_unlock();
2262 2331