@@ -268,6 +268,8 @@ enum macvlan_mode {
/* SR-IOV virtual function management section */
+#define SELF_VF -1
+
enum {
IFLA_VF_INFO_UNSPEC,
IFLA_VF_INFO,
@@ -1294,6 +1294,66 @@ static int do_set_master(struct net_device *dev, int ifindex)
return 0;
}
+static int do_set_rx_filter(struct net_device *dev, int vf,
+ struct nlattr *rx_filter[],
+ int *modified)
+{
+ const struct net_device_ops *ops = dev->netdev_ops;
+ int err = 0;
+
+ if (rx_filter[IFLA_RX_FILTER_ADDR]) {
+ struct nlattr *addr_filter[IFLA_RX_FILTER_ADDR_MAX+1];
+
+ if (!ops->ndo_set_rx_filter_addr) {
+ err = -EOPNOTSUPP;
+ goto errout;
+ }
+
+ err = nla_parse_nested(addr_filter, IFLA_RX_FILTER_ADDR_MAX,
+ rx_filter[IFLA_RX_FILTER_ADDR],
+ ifla_addr_filter_policy);
+ if (err < 0)
+ goto errout;
+
+ if (addr_filter[IFLA_RX_FILTER_ADDR_FLAGS]) {
+ unsigned int flags = nla_get_u32(
+ addr_filter[IFLA_RX_FILTER_ADDR_FLAGS]);
+ if (flags & ~RX_FILTER_FLAGS) {
+ err = -EINVAL;
+ goto errout;
+ }
+ }
+
+ err = ops->ndo_set_rx_filter_addr(dev, vf, addr_filter);
+ if (err < 0)
+ goto errout;
+ *modified = 1;
+ }
+
+ if (rx_filter[IFLA_RX_FILTER_VLAN]) {
+ struct nlattr *vlan_filter[IFLA_RX_FILTER_VLAN_MAX+1];
+
+ if (!ops->ndo_set_rx_filter_vlan) {
+ err = -EOPNOTSUPP;
+ goto errout;
+ }
+
+ err = nla_parse_nested(vlan_filter, IFLA_RX_FILTER_VLAN_MAX,
+ rx_filter[IFLA_RX_FILTER_VLAN],
+ ifla_vlan_filter_policy);
+ if (err < 0)
+ goto errout;
+
+ err = ops->ndo_set_rx_filter_vlan(dev, vf, vlan_filter);
+ if (err < 0)
+ goto errout;
+ *modified = 1;
+ }
+
+errout:
+ return err;
+}
+
static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
struct nlattr **tb, char *ifname, int modified)
{
@@ -1515,6 +1575,47 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
modified = 1;
}
}
+
+ if (tb[IFLA_VF_RX_FILTERS]) {
+ struct nlattr *vf_rx_filter[IFLA_RX_FILTER_MAX+1];
+ struct nlattr *attr;
+ int vf;
+ int rem;
+
+ nla_for_each_nested(attr, tb[IFLA_VF_RX_FILTERS], rem) {
+ if (nla_type(attr) != IFLA_VF_RX_FILTER)
+ continue;
+ err = nla_parse_nested(vf_rx_filter, IFLA_RX_FILTER_MAX,
+ attr, ifla_rx_filter_policy);
+ if (err < 0)
+ goto errout;
+
+ if (!vf_rx_filter[IFLA_RX_FILTER_VF]) {
+ err = -EOPNOTSUPP;
+ goto errout;
+ }
+ vf = nla_get_u32(vf_rx_filter[IFLA_RX_FILTER_VF]);
+
+ err = do_set_rx_filter(dev, vf, vf_rx_filter,
+ &modified);
+ if (err < 0)
+ goto errout;
+ }
+ }
+
+ if (tb[IFLA_RX_FILTER]) {
+ struct nlattr *rx_filter[IFLA_RX_FILTER_MAX+1];
+
+ err = nla_parse_nested(rx_filter, IFLA_RX_FILTER_MAX,
+ tb[IFLA_RX_FILTER], ifla_rx_filter_policy);
+ if (err < 0)
+ goto errout;
+
+ err = do_set_rx_filter(dev, SELF_VF, rx_filter, &modified);
+ if (err < 0)
+ goto errout;
+ }
+
err = 0;
errout: