X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fbrcompat.c;h=92fcecc216719dce8eb274b96ffb5210c95491ae;hb=716346cb67b705a164a2203ab38aefe4a84cd826;hp=d945e4e6de9328b08f6befffbf3794e82fab5083;hpb=e5307f55aa89b7ade27cb4bf92223c3b9c099eef;p=sliver-openvswitch.git diff --git a/datapath/brcompat.c b/datapath/brcompat.c index d945e4e6d..92fcecc21 100644 --- a/datapath/brcompat.c +++ b/datapath/brcompat.c @@ -9,10 +9,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -20,9 +18,7 @@ #include "compat.h" #include "openvswitch/brcompat-netlink.h" #include "brc_procfs.h" -#include "brc_sysfs.h" #include "datapath.h" -#include "dp_dev.h" static struct genl_family brc_genl_family; static struct genl_multicast_group brc_mc_group; @@ -46,36 +42,6 @@ static u32 brc_seq; /* Sequence number for current op. */ static struct sk_buff *brc_send_command(struct sk_buff *, struct nlattr **attrs); static int brc_send_simple_command(struct sk_buff *); -static int -get_dp_ifindices(int *indices, int num) -{ - int i, index = 0; - - rcu_read_lock(); - for (i=0; i < ODP_MAX && index < num; i++) { - struct datapath *dp = get_dp(i); - if (!dp) - continue; - indices[index++] = dp->ports[ODPP_LOCAL]->dev->ifindex; - } - rcu_read_unlock(); - - return index; -} - -static void -get_port_ifindices(struct datapath *dp, int *ifindices, int num) -{ - struct net_bridge_port *p; - - rcu_read_lock(); - list_for_each_entry_rcu (p, &dp->port_list, node) { - if (p->port_no < num) - ifindices[p->port_no] = p->dev->ifindex; - } - rcu_read_unlock(); -} - static struct sk_buff * brc_make_request(int op, const char *bridge, const char *port) { @@ -84,7 +50,8 @@ brc_make_request(int op, const char *bridge, const char *port) goto error; genlmsg_put(skb, 0, 0, &brc_genl_family, 0, op); - NLA_PUT_STRING(skb, BRC_GENL_A_DP_NAME, bridge); + if (bridge) + NLA_PUT_STRING(skb, BRC_GENL_A_DP_NAME, bridge); if (port) NLA_PUT_STRING(skb, BRC_GENL_A_PORT_NAME, port); return skb; @@ -127,26 +94,57 @@ static int brc_add_del_bridge(char __user *uname, int add) return brc_send_simple_command(request); } -static int brc_get_bridges(int __user *uindices, int n) +static int brc_get_indices(int op, const char *br_name, + int __user *uindices, int n) { + struct nlattr *attrs[BRC_GENL_A_MAX + 1]; + struct sk_buff *request, *reply; int *indices; int ret; + int len; + if (n < 0) + return -EINVAL; if (n >= 2048) return -ENOMEM; - indices = kcalloc(n, sizeof(int), GFP_KERNEL); - if (indices == NULL) + request = brc_make_request(op, br_name, NULL); + if (!request) return -ENOMEM; - n = get_dp_ifindices(indices, n); + reply = brc_send_command(request, attrs); + ret = PTR_ERR(reply); + if (IS_ERR(reply)) + goto exit; + + ret = -nla_get_u32(attrs[BRC_GENL_A_ERR_CODE]); + if (ret < 0) + goto exit_free_skb; + ret = -EINVAL; + if (!attrs[BRC_GENL_A_IFINDEXES]) + goto exit_free_skb; + + len = nla_len(attrs[BRC_GENL_A_IFINDEXES]); + indices = nla_data(attrs[BRC_GENL_A_IFINDEXES]); + if (len % sizeof(int)) + goto exit_free_skb; + + n = min_t(int, n, len / sizeof(int)); ret = copy_to_user(uindices, indices, n * sizeof(int)) ? -EFAULT : n; - kfree(indices); +exit_free_skb: + kfree_skb(reply); +exit: return ret; } +/* Called with br_ioctl_mutex. */ +static int brc_get_bridges(int __user *uindices, int n) +{ + return brc_get_indices(BRC_GENL_C_GET_BRIDGES, NULL, uindices, n); +} + /* Legacy deviceless bridge ioctl's. Called with br_ioctl_mutex. */ static int old_deviceless(void __user *uarg) @@ -239,26 +237,72 @@ brc_get_bridge_info(struct net_device *dev, struct __bridge_info __user *ub) static int brc_get_port_list(struct net_device *dev, int __user *uindices, int num) { - struct dp_dev *dp_dev = netdev_priv(dev); - struct datapath *dp = dp_dev->dp; - int *indices; + int retval; - if (num < 0) - return -EINVAL; - if (num == 0) - num = 256; - if (num > DP_MAX_PORTS) - num = DP_MAX_PORTS; + rtnl_unlock(); + retval = brc_get_indices(BRC_GENL_C_GET_PORTS, dev->name, + uindices, num); + rtnl_lock(); + + return retval; +} + +/* + * Format up to a page worth of forwarding table entries + * userbuf -- where to copy result + * maxnum -- maximum number of entries desired + * (limited to a page for sanity) + * offset -- number of records to skip + */ +static int brc_get_fdb_entries(struct net_device *dev, void __user *userbuf, + unsigned long maxnum, unsigned long offset) +{ + struct nlattr *attrs[BRC_GENL_A_MAX + 1]; + struct sk_buff *request, *reply; + int retval; + int len; - indices = kcalloc(num, sizeof(int), GFP_KERNEL); - if (indices == NULL) + /* Clamp size to PAGE_SIZE, test maxnum to avoid overflow */ + if (maxnum > PAGE_SIZE/sizeof(struct __fdb_entry)) + maxnum = PAGE_SIZE/sizeof(struct __fdb_entry); + + request = brc_make_request(BRC_GENL_C_FDB_QUERY, dev->name, NULL); + if (!request) return -ENOMEM; + NLA_PUT_U64(request, BRC_GENL_A_FDB_COUNT, maxnum); + NLA_PUT_U64(request, BRC_GENL_A_FDB_SKIP, offset); + + rtnl_unlock(); + reply = brc_send_command(request, attrs); + retval = PTR_ERR(reply); + if (IS_ERR(reply)) + goto exit; + + retval = -nla_get_u32(attrs[BRC_GENL_A_ERR_CODE]); + if (retval < 0) + goto exit_free_skb; + + retval = -EINVAL; + if (!attrs[BRC_GENL_A_FDB_DATA]) + goto exit_free_skb; + len = nla_len(attrs[BRC_GENL_A_FDB_DATA]); + if (len % sizeof(struct __fdb_entry) || + len / sizeof(struct __fdb_entry) > maxnum) + goto exit_free_skb; + + retval = len / sizeof(struct __fdb_entry); + if (copy_to_user(userbuf, nla_data(attrs[BRC_GENL_A_FDB_DATA]), len)) + retval = -EFAULT; - get_port_ifindices(dp, indices, num); - if (copy_to_user(uindices, indices, num * sizeof(int))) - num = -EFAULT; - kfree(indices); - return num; +exit_free_skb: + kfree_skb(reply); +exit: + rtnl_lock(); + return retval; + +nla_put_failure: + kfree_skb(request); + return -ENOMEM; } /* Legacy ioctl's through SIOCDEVPRIVATE. Called with rtnl_lock. */ @@ -281,6 +325,10 @@ old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case BRCTL_GET_PORT_LIST: return brc_get_port_list(dev, (int __user *)args[1], args[2]); + + case BRCTL_GET_FDB_ENTRIES: + return brc_get_fdb_entries(dev, (void __user *)args[1], + args[2], args[3]); } return -EOPNOTSUPP; @@ -357,9 +405,12 @@ static struct genl_ops brc_genl_ops_query_dp = { /* Attribute policy: what each attribute may contain. */ static struct nla_policy brc_genl_policy[BRC_GENL_A_MAX + 1] = { [BRC_GENL_A_ERR_CODE] = { .type = NLA_U32 }, + [BRC_GENL_A_PROC_DIR] = { .type = NLA_NUL_STRING }, [BRC_GENL_A_PROC_NAME] = { .type = NLA_NUL_STRING }, [BRC_GENL_A_PROC_DATA] = { .type = NLA_NUL_STRING }, + + [BRC_GENL_A_FDB_DATA] = { .type = NLA_UNSPEC }, }; static int @@ -458,61 +509,19 @@ error: return ERR_PTR(error); } -int brc_add_dp(struct datapath *dp) -{ - if (!try_module_get(THIS_MODULE)) - return -ENODEV; -#ifdef SUPPORT_SYSFS - brc_sysfs_add_dp(dp); -#endif - - return 0; -} - -int brc_del_dp(struct datapath *dp) -{ -#ifdef SUPPORT_SYSFS - brc_sysfs_del_dp(dp); -#endif - module_put(THIS_MODULE); - - return 0; -} - static int __init brc_init(void) { - int i; int err; printk("Open vSwitch Bridge Compatibility, built "__DATE__" "__TIME__"\n"); - rcu_read_lock(); - for (i=0; i