diff options
-rw-r--r-- | include/linux/if_link.h | 75 | ||||
-rw-r--r-- | include/linux/netdevice.h | 8 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 169 |
3 files changed, 251 insertions, 1 deletions
diff --git a/include/linux/if_link.h b/include/linux/if_link.h index c3af67fce3f2..85c812db5a3f 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h | |||
@@ -113,6 +113,8 @@ enum { | |||
113 | IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */ | 113 | IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */ |
114 | IFLA_VFINFO_LIST, | 114 | IFLA_VFINFO_LIST, |
115 | IFLA_STATS64, | 115 | IFLA_STATS64, |
116 | IFLA_VF_PORTS, | ||
117 | IFLA_PORT_SELF, | ||
116 | __IFLA_MAX | 118 | __IFLA_MAX |
117 | }; | 119 | }; |
118 | 120 | ||
@@ -274,4 +276,77 @@ struct ifla_vf_info { | |||
274 | __u32 qos; | 276 | __u32 qos; |
275 | __u32 tx_rate; | 277 | __u32 tx_rate; |
276 | }; | 278 | }; |
279 | |||
280 | /* VF ports management section | ||
281 | * | ||
282 | * Nested layout of set/get msg is: | ||
283 | * | ||
284 | * [IFLA_NUM_VF] | ||
285 | * [IFLA_VF_PORTS] | ||
286 | * [IFLA_VF_PORT] | ||
287 | * [IFLA_PORT_*], ... | ||
288 | * [IFLA_VF_PORT] | ||
289 | * [IFLA_PORT_*], ... | ||
290 | * ... | ||
291 | * [IFLA_PORT_SELF] | ||
292 | * [IFLA_PORT_*], ... | ||
293 | */ | ||
294 | |||
295 | enum { | ||
296 | IFLA_VF_PORT_UNSPEC, | ||
297 | IFLA_VF_PORT, /* nest */ | ||
298 | __IFLA_VF_PORT_MAX, | ||
299 | }; | ||
300 | |||
301 | #define IFLA_VF_PORT_MAX (__IFLA_VF_PORT_MAX - 1) | ||
302 | |||
303 | enum { | ||
304 | IFLA_PORT_UNSPEC, | ||
305 | IFLA_PORT_VF, /* __u32 */ | ||
306 | IFLA_PORT_PROFILE, /* string */ | ||
307 | IFLA_PORT_VSI_TYPE, /* 802.1Qbg (pre-)standard VDP */ | ||
308 | IFLA_PORT_INSTANCE_UUID, /* binary UUID */ | ||
309 | IFLA_PORT_HOST_UUID, /* binary UUID */ | ||
310 | IFLA_PORT_REQUEST, /* __u8 */ | ||
311 | IFLA_PORT_RESPONSE, /* __u16, output only */ | ||
312 | __IFLA_PORT_MAX, | ||
313 | }; | ||
314 | |||
315 | #define IFLA_PORT_MAX (__IFLA_PORT_MAX - 1) | ||
316 | |||
317 | #define PORT_PROFILE_MAX 40 | ||
318 | #define PORT_UUID_MAX 16 | ||
319 | #define PORT_SELF_VF -1 | ||
320 | |||
321 | enum { | ||
322 | PORT_REQUEST_PREASSOCIATE = 0, | ||
323 | PORT_REQUEST_PREASSOCIATE_RR, | ||
324 | PORT_REQUEST_ASSOCIATE, | ||
325 | PORT_REQUEST_DISASSOCIATE, | ||
326 | }; | ||
327 | |||
328 | enum { | ||
329 | PORT_VDP_RESPONSE_SUCCESS = 0, | ||
330 | PORT_VDP_RESPONSE_INVALID_FORMAT, | ||
331 | PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES, | ||
332 | PORT_VDP_RESPONSE_UNUSED_VTID, | ||
333 | PORT_VDP_RESPONSE_VTID_VIOLATION, | ||
334 | PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION, | ||
335 | PORT_VDP_RESPONSE_OUT_OF_SYNC, | ||
336 | /* 0x08-0xFF reserved for future VDP use */ | ||
337 | PORT_PROFILE_RESPONSE_SUCCESS = 0x100, | ||
338 | PORT_PROFILE_RESPONSE_INPROGRESS, | ||
339 | PORT_PROFILE_RESPONSE_INVALID, | ||
340 | PORT_PROFILE_RESPONSE_BADSTATE, | ||
341 | PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES, | ||
342 | PORT_PROFILE_RESPONSE_ERROR, | ||
343 | }; | ||
344 | |||
345 | struct ifla_port_vsi { | ||
346 | __u8 vsi_mgr_id; | ||
347 | __u8 vsi_type_id[3]; | ||
348 | __u8 vsi_type_version; | ||
349 | __u8 pad[3]; | ||
350 | }; | ||
351 | |||
277 | #endif /* _LINUX_IF_LINK_H */ | 352 | #endif /* _LINUX_IF_LINK_H */ |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c1b2341897c2..c3487a6bdf99 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -686,6 +686,9 @@ struct netdev_rx_queue { | |||
686 | * int (*ndo_set_vf_tx_rate)(struct net_device *dev, int vf, int rate); | 686 | * int (*ndo_set_vf_tx_rate)(struct net_device *dev, int vf, int rate); |
687 | * int (*ndo_get_vf_config)(struct net_device *dev, | 687 | * int (*ndo_get_vf_config)(struct net_device *dev, |
688 | * int vf, struct ifla_vf_info *ivf); | 688 | * int vf, struct ifla_vf_info *ivf); |
689 | * int (*ndo_set_vf_port)(struct net_device *dev, int vf, | ||
690 | * struct nlattr *port[]); | ||
691 | * int (*ndo_get_vf_port)(struct net_device *dev, int vf, struct sk_buff *skb); | ||
689 | */ | 692 | */ |
690 | #define HAVE_NET_DEVICE_OPS | 693 | #define HAVE_NET_DEVICE_OPS |
691 | struct net_device_ops { | 694 | struct net_device_ops { |
@@ -735,6 +738,11 @@ struct net_device_ops { | |||
735 | int (*ndo_get_vf_config)(struct net_device *dev, | 738 | int (*ndo_get_vf_config)(struct net_device *dev, |
736 | int vf, | 739 | int vf, |
737 | struct ifla_vf_info *ivf); | 740 | struct ifla_vf_info *ivf); |
741 | int (*ndo_set_vf_port)(struct net_device *dev, | ||
742 | int vf, | ||
743 | struct nlattr *port[]); | ||
744 | int (*ndo_get_vf_port)(struct net_device *dev, | ||
745 | int vf, struct sk_buff *skb); | ||
738 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) | 746 | #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) |
739 | int (*ndo_fcoe_enable)(struct net_device *dev); | 747 | int (*ndo_fcoe_enable)(struct net_device *dev); |
740 | int (*ndo_fcoe_disable)(struct net_device *dev); | 748 | int (*ndo_fcoe_disable)(struct net_device *dev); |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 66db1201da9b..e4b9870e4706 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -660,6 +660,31 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev) | |||
660 | return 0; | 660 | return 0; |
661 | } | 661 | } |
662 | 662 | ||
663 | static size_t rtnl_port_size(const struct net_device *dev) | ||
664 | { | ||
665 | size_t port_size = nla_total_size(4) /* PORT_VF */ | ||
666 | + nla_total_size(PORT_PROFILE_MAX) /* PORT_PROFILE */ | ||
667 | + nla_total_size(sizeof(struct ifla_port_vsi)) | ||
668 | /* PORT_VSI_TYPE */ | ||
669 | + nla_total_size(PORT_UUID_MAX) /* PORT_INSTANCE_UUID */ | ||
670 | + nla_total_size(PORT_UUID_MAX) /* PORT_HOST_UUID */ | ||
671 | + nla_total_size(1) /* PROT_VDP_REQUEST */ | ||
672 | + nla_total_size(2); /* PORT_VDP_RESPONSE */ | ||
673 | size_t vf_ports_size = nla_total_size(sizeof(struct nlattr)); | ||
674 | size_t vf_port_size = nla_total_size(sizeof(struct nlattr)) | ||
675 | + port_size; | ||
676 | size_t port_self_size = nla_total_size(sizeof(struct nlattr)) | ||
677 | + port_size; | ||
678 | |||
679 | if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent) | ||
680 | return 0; | ||
681 | if (dev_num_vf(dev->dev.parent)) | ||
682 | return port_self_size + vf_ports_size + | ||
683 | vf_port_size * dev_num_vf(dev->dev.parent); | ||
684 | else | ||
685 | return port_self_size; | ||
686 | } | ||
687 | |||
663 | static inline size_t if_nlmsg_size(const struct net_device *dev) | 688 | static inline size_t if_nlmsg_size(const struct net_device *dev) |
664 | { | 689 | { |
665 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) | 690 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) |
@@ -680,9 +705,82 @@ static inline size_t if_nlmsg_size(const struct net_device *dev) | |||
680 | + nla_total_size(1) /* IFLA_LINKMODE */ | 705 | + nla_total_size(1) /* IFLA_LINKMODE */ |
681 | + nla_total_size(4) /* IFLA_NUM_VF */ | 706 | + nla_total_size(4) /* IFLA_NUM_VF */ |
682 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ | 707 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ |
708 | + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ | ||
683 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ | 709 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ |
684 | } | 710 | } |
685 | 711 | ||
712 | static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) | ||
713 | { | ||
714 | struct nlattr *vf_ports; | ||
715 | struct nlattr *vf_port; | ||
716 | int vf; | ||
717 | int err; | ||
718 | |||
719 | vf_ports = nla_nest_start(skb, IFLA_VF_PORTS); | ||
720 | if (!vf_ports) | ||
721 | return -EMSGSIZE; | ||
722 | |||
723 | for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++) { | ||
724 | vf_port = nla_nest_start(skb, IFLA_VF_PORT); | ||
725 | if (!vf_port) { | ||
726 | nla_nest_cancel(skb, vf_ports); | ||
727 | return -EMSGSIZE; | ||
728 | } | ||
729 | NLA_PUT_U32(skb, IFLA_PORT_VF, vf); | ||
730 | err = dev->netdev_ops->ndo_get_vf_port(dev, vf, skb); | ||
731 | if (err) { | ||
732 | nla_put_failure: | ||
733 | nla_nest_cancel(skb, vf_port); | ||
734 | continue; | ||
735 | } | ||
736 | nla_nest_end(skb, vf_port); | ||
737 | } | ||
738 | |||
739 | nla_nest_end(skb, vf_ports); | ||
740 | |||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev) | ||
745 | { | ||
746 | struct nlattr *port_self; | ||
747 | int err; | ||
748 | |||
749 | port_self = nla_nest_start(skb, IFLA_PORT_SELF); | ||
750 | if (!port_self) | ||
751 | return -EMSGSIZE; | ||
752 | |||
753 | err = dev->netdev_ops->ndo_get_vf_port(dev, PORT_SELF_VF, skb); | ||
754 | if (err) { | ||
755 | nla_nest_cancel(skb, port_self); | ||
756 | return err; | ||
757 | } | ||
758 | |||
759 | nla_nest_end(skb, port_self); | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev) | ||
765 | { | ||
766 | int err; | ||
767 | |||
768 | if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent) | ||
769 | return 0; | ||
770 | |||
771 | err = rtnl_port_self_fill(skb, dev); | ||
772 | if (err) | ||
773 | return err; | ||
774 | |||
775 | if (dev_num_vf(dev->dev.parent)) { | ||
776 | err = rtnl_vf_ports_fill(skb, dev); | ||
777 | if (err) | ||
778 | return err; | ||
779 | } | ||
780 | |||
781 | return 0; | ||
782 | } | ||
783 | |||
686 | static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | 784 | static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, |
687 | int type, u32 pid, u32 seq, u32 change, | 785 | int type, u32 pid, u32 seq, u32 change, |
688 | unsigned int flags) | 786 | unsigned int flags) |
@@ -754,13 +852,15 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
754 | goto nla_put_failure; | 852 | goto nla_put_failure; |
755 | copy_rtnl_link_stats64(nla_data(attr), stats); | 853 | copy_rtnl_link_stats64(nla_data(attr), stats); |
756 | 854 | ||
855 | if (dev->dev.parent) | ||
856 | NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)); | ||
857 | |||
757 | if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { | 858 | if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { |
758 | int i; | 859 | int i; |
759 | 860 | ||
760 | struct nlattr *vfinfo, *vf; | 861 | struct nlattr *vfinfo, *vf; |
761 | int num_vfs = dev_num_vf(dev->dev.parent); | 862 | int num_vfs = dev_num_vf(dev->dev.parent); |
762 | 863 | ||
763 | NLA_PUT_U32(skb, IFLA_NUM_VF, num_vfs); | ||
764 | vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); | 864 | vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); |
765 | if (!vfinfo) | 865 | if (!vfinfo) |
766 | goto nla_put_failure; | 866 | goto nla_put_failure; |
@@ -788,6 +888,10 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
788 | } | 888 | } |
789 | nla_nest_end(skb, vfinfo); | 889 | nla_nest_end(skb, vfinfo); |
790 | } | 890 | } |
891 | |||
892 | if (rtnl_port_fill(skb, dev)) | ||
893 | goto nla_put_failure; | ||
894 | |||
791 | if (dev->rtnl_link_ops) { | 895 | if (dev->rtnl_link_ops) { |
792 | if (rtnl_link_fill(skb, dev) < 0) | 896 | if (rtnl_link_fill(skb, dev) < 0) |
793 | goto nla_put_failure; | 897 | goto nla_put_failure; |
@@ -849,6 +953,8 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
849 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, | 953 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, |
850 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, | 954 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, |
851 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, | 955 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, |
956 | [IFLA_VF_PORTS] = { .type = NLA_NESTED }, | ||
957 | [IFLA_PORT_SELF] = { .type = NLA_NESTED }, | ||
852 | }; | 958 | }; |
853 | EXPORT_SYMBOL(ifla_policy); | 959 | EXPORT_SYMBOL(ifla_policy); |
854 | 960 | ||
@@ -870,6 +976,20 @@ static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { | |||
870 | .len = sizeof(struct ifla_vf_tx_rate) }, | 976 | .len = sizeof(struct ifla_vf_tx_rate) }, |
871 | }; | 977 | }; |
872 | 978 | ||
979 | static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = { | ||
980 | [IFLA_PORT_VF] = { .type = NLA_U32 }, | ||
981 | [IFLA_PORT_PROFILE] = { .type = NLA_STRING, | ||
982 | .len = PORT_PROFILE_MAX }, | ||
983 | [IFLA_PORT_VSI_TYPE] = { .type = NLA_BINARY, | ||
984 | .len = sizeof(struct ifla_port_vsi)}, | ||
985 | [IFLA_PORT_INSTANCE_UUID] = { .type = NLA_BINARY, | ||
986 | .len = PORT_UUID_MAX }, | ||
987 | [IFLA_PORT_HOST_UUID] = { .type = NLA_STRING, | ||
988 | .len = PORT_UUID_MAX }, | ||
989 | [IFLA_PORT_REQUEST] = { .type = NLA_U8, }, | ||
990 | [IFLA_PORT_RESPONSE] = { .type = NLA_U16, }, | ||
991 | }; | ||
992 | |||
873 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) | 993 | struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) |
874 | { | 994 | { |
875 | struct net *net; | 995 | struct net *net; |
@@ -1089,6 +1209,53 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1089 | } | 1209 | } |
1090 | err = 0; | 1210 | err = 0; |
1091 | 1211 | ||
1212 | if (tb[IFLA_VF_PORTS]) { | ||
1213 | struct nlattr *port[IFLA_PORT_MAX+1]; | ||
1214 | struct nlattr *attr; | ||
1215 | int vf; | ||
1216 | int rem; | ||
1217 | |||
1218 | err = -EOPNOTSUPP; | ||
1219 | if (!ops->ndo_set_vf_port) | ||
1220 | goto errout; | ||
1221 | |||
1222 | nla_for_each_nested(attr, tb[IFLA_VF_PORTS], rem) { | ||
1223 | if (nla_type(attr) != IFLA_VF_PORT) | ||
1224 | continue; | ||
1225 | err = nla_parse_nested(port, IFLA_PORT_MAX, | ||
1226 | attr, ifla_port_policy); | ||
1227 | if (err < 0) | ||
1228 | goto errout; | ||
1229 | if (!port[IFLA_PORT_VF]) { | ||
1230 | err = -EOPNOTSUPP; | ||
1231 | goto errout; | ||
1232 | } | ||
1233 | vf = nla_get_u32(port[IFLA_PORT_VF]); | ||
1234 | err = ops->ndo_set_vf_port(dev, vf, port); | ||
1235 | if (err < 0) | ||
1236 | goto errout; | ||
1237 | modified = 1; | ||
1238 | } | ||
1239 | } | ||
1240 | err = 0; | ||
1241 | |||
1242 | if (tb[IFLA_PORT_SELF]) { | ||
1243 | struct nlattr *port[IFLA_PORT_MAX+1]; | ||
1244 | |||
1245 | err = nla_parse_nested(port, IFLA_PORT_MAX, | ||
1246 | tb[IFLA_PORT_SELF], ifla_port_policy); | ||
1247 | if (err < 0) | ||
1248 | goto errout; | ||
1249 | |||
1250 | err = -EOPNOTSUPP; | ||
1251 | if (ops->ndo_set_vf_port) | ||
1252 | err = ops->ndo_set_vf_port(dev, PORT_SELF_VF, port); | ||
1253 | if (err < 0) | ||
1254 | goto errout; | ||
1255 | modified = 1; | ||
1256 | } | ||
1257 | err = 0; | ||
1258 | |||
1092 | errout: | 1259 | errout: |
1093 | if (err < 0 && modified && net_ratelimit()) | 1260 | if (err < 0 && modified && net_ratelimit()) |
1094 | printk(KERN_WARNING "A link change request failed with " | 1261 | printk(KERN_WARNING "A link change request failed with " |