aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/rtnetlink.h9
-rw-r--r--net/core/rtnetlink.c81
2 files changed, 84 insertions, 6 deletions
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 489dd7bb28ec..f28544b2f9af 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -69,6 +69,15 @@ extern int ndo_dflt_fdb_dump(struct sk_buff *skb,
69 struct netlink_callback *cb, 69 struct netlink_callback *cb,
70 struct net_device *dev, 70 struct net_device *dev,
71 int idx); 71 int idx);
72extern 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);
77extern int ndo_dflt_fdb_del(struct ndmsg *ndm,
78 struct nlattr *tb[],
79 struct net_device *dev,
80 const unsigned char *addr);
72 81
73extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, 82extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
74 struct net_device *dev, u16 mode); 83 struct net_device *dev, u16 mode);
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