diff options
author | Vlad Yasevich <vyasevic@redhat.com> | 2013-03-06 10:39:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-03-07 15:29:45 -0500 |
commit | 090096bf3db1c281ddd034573260045888a68fea (patch) | |
tree | abadf4a4ebdc4177ac59c32818fc73a9ba2a492b /net | |
parent | 6906f4ed6f85b2d72fd944e15da6a905fdde8b40 (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.c | 81 |
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 | */ | ||
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 | static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2083 | static 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 | */ | ||
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 | static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2181 | static 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 | ||