summaryrefslogtreecommitdiffstats
path: root/net/ncsi/ncsi-netlink.c
diff options
context:
space:
mode:
authorSamuel Mendoza-Jonas <sam@mendozajonas.com>2018-11-15 23:51:59 -0500
committerDavid S. Miller <davem@davemloft.net>2018-11-18 00:09:49 -0500
commit8d951a75d022d94a05f5fa74217670a981e8302d (patch)
treed360d9898e404a423779ba2b3ced1a5801515997 /net/ncsi/ncsi-netlink.c
parent2878a2cfe57a5db21844801cf502fe535a3134b2 (diff)
net/ncsi: Configure multi-package, multi-channel modes with failover
This patch extends the ncsi-netlink interface with two new commands and three new attributes to configure multiple packages and/or channels at once, and configure specific failover modes. NCSI_CMD_SET_PACKAGE mask and NCSI_CMD_SET_CHANNEL_MASK set a whitelist of packages or channels allowed to be configured with the NCSI_ATTR_PACKAGE_MASK and NCSI_ATTR_CHANNEL_MASK attributes respectively. If one of these whitelists is set only packages or channels matching the whitelist are considered for the channel queue in ncsi_choose_active_channel(). These commands may also use the NCSI_ATTR_MULTI_FLAG to signal that multiple packages or channels may be configured simultaneously. NCSI hardware arbitration (HWA) must be available in order to enable multi-package mode. Multi-channel mode is always available. If the NCSI_ATTR_CHANNEL_ID attribute is present in the NCSI_CMD_SET_CHANNEL_MASK command the it sets the preferred channel as with the NCSI_CMD_SET_INTERFACE command. The combination of preferred channel and channel whitelist defines a primary channel and the allowed failover channels. If the NCSI_ATTR_MULTI_FLAG attribute is also present then the preferred channel is configured for Tx/Rx and the other channels are enabled only for Rx. Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ncsi/ncsi-netlink.c')
-rw-r--r--net/ncsi/ncsi-netlink.c221
1 files changed, 193 insertions, 28 deletions
diff --git a/net/ncsi/ncsi-netlink.c b/net/ncsi/ncsi-netlink.c
index cde48fe43dba..5d782445d2fc 100644
--- a/net/ncsi/ncsi-netlink.c
+++ b/net/ncsi/ncsi-netlink.c
@@ -30,6 +30,9 @@ static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = {
30 [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 }, 30 [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 },
31 [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 }, 31 [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 },
32 [NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 }, 32 [NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 },
33 [NCSI_ATTR_MULTI_FLAG] = { .type = NLA_FLAG },
34 [NCSI_ATTR_PACKAGE_MASK] = { .type = NLA_U32 },
35 [NCSI_ATTR_CHANNEL_MASK] = { .type = NLA_U32 },
33}; 36};
34 37
35static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex) 38static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex)
@@ -69,7 +72,7 @@ static int ncsi_write_channel_info(struct sk_buff *skb,
69 nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]); 72 nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]);
70 if (nc->state == NCSI_CHANNEL_ACTIVE) 73 if (nc->state == NCSI_CHANNEL_ACTIVE)
71 nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE); 74 nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE);
72 if (ndp->force_channel == nc) 75 if (nc == nc->package->preferred_channel)
73 nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED); 76 nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED);
74 77
75 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version); 78 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version);
@@ -114,7 +117,7 @@ static int ncsi_write_package_info(struct sk_buff *skb,
114 if (!pnest) 117 if (!pnest)
115 return -ENOMEM; 118 return -ENOMEM;
116 nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id); 119 nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id);
117 if (ndp->force_package == np) 120 if ((0x1 << np->id) == ndp->package_whitelist)
118 nla_put_flag(skb, NCSI_PKG_ATTR_FORCED); 121 nla_put_flag(skb, NCSI_PKG_ATTR_FORCED);
119 cnest = nla_nest_start(skb, NCSI_PKG_ATTR_CHANNEL_LIST); 122 cnest = nla_nest_start(skb, NCSI_PKG_ATTR_CHANNEL_LIST);
120 if (!cnest) { 123 if (!cnest) {
@@ -290,45 +293,54 @@ static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info)
290 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 293 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
291 package = NULL; 294 package = NULL;
292 295
293 spin_lock_irqsave(&ndp->lock, flags);
294
295 NCSI_FOR_EACH_PACKAGE(ndp, np) 296 NCSI_FOR_EACH_PACKAGE(ndp, np)
296 if (np->id == package_id) 297 if (np->id == package_id)
297 package = np; 298 package = np;
298 if (!package) { 299 if (!package) {
299 /* The user has set a package that does not exist */ 300 /* The user has set a package that does not exist */
300 spin_unlock_irqrestore(&ndp->lock, flags);
301 return -ERANGE; 301 return -ERANGE;
302 } 302 }
303 303
304 channel = NULL; 304 channel = NULL;
305 if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) { 305 if (info->attrs[NCSI_ATTR_CHANNEL_ID]) {
306 /* Allow any channel */
307 channel_id = NCSI_RESERVED_CHANNEL;
308 } else {
309 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]); 306 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
310 NCSI_FOR_EACH_CHANNEL(package, nc) 307 NCSI_FOR_EACH_CHANNEL(package, nc)
311 if (nc->id == channel_id) 308 if (nc->id == channel_id) {
312 channel = nc; 309 channel = nc;
310 break;
311 }
312 if (!channel) {
313 netdev_info(ndp->ndev.dev,
314 "NCSI: Channel %u does not exist!\n",
315 channel_id);
316 return -ERANGE;
317 }
313 } 318 }
314 319
315 if (channel_id != NCSI_RESERVED_CHANNEL && !channel) { 320 spin_lock_irqsave(&ndp->lock, flags);
316 /* The user has set a channel that does not exist on this 321 ndp->package_whitelist = 0x1 << package->id;
317 * package 322 ndp->multi_package = false;
318 */
319 spin_unlock_irqrestore(&ndp->lock, flags);
320 netdev_info(ndp->ndev.dev, "NCSI: Channel %u does not exist!\n",
321 channel_id);
322 return -ERANGE;
323 }
324
325 ndp->force_package = package;
326 ndp->force_channel = channel;
327 spin_unlock_irqrestore(&ndp->lock, flags); 323 spin_unlock_irqrestore(&ndp->lock, flags);
328 324
329 netdev_info(ndp->ndev.dev, "Set package 0x%x, channel 0x%x%s as preferred\n", 325 spin_lock_irqsave(&package->lock, flags);
330 package_id, channel_id, 326 package->multi_channel = false;
331 channel_id == NCSI_RESERVED_CHANNEL ? " (any)" : ""); 327 if (channel) {
328 package->channel_whitelist = 0x1 << channel->id;
329 package->preferred_channel = channel;
330 } else {
331 /* Allow any channel */
332 package->channel_whitelist = UINT_MAX;
333 package->preferred_channel = NULL;
334 }
335 spin_unlock_irqrestore(&package->lock, flags);
336
337 if (channel)
338 netdev_info(ndp->ndev.dev,
339 "Set package 0x%x, channel 0x%x as preferred\n",
340 package_id, channel_id);
341 else
342 netdev_info(ndp->ndev.dev, "Set package 0x%x as preferred\n",
343 package_id);
332 344
333 /* Update channel configuration */ 345 /* Update channel configuration */
334 if (!(ndp->flags & NCSI_DEV_RESET)) 346 if (!(ndp->flags & NCSI_DEV_RESET))
@@ -340,6 +352,7 @@ static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info)
340static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info) 352static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
341{ 353{
342 struct ncsi_dev_priv *ndp; 354 struct ncsi_dev_priv *ndp;
355 struct ncsi_package *np;
343 unsigned long flags; 356 unsigned long flags;
344 357
345 if (!info || !info->attrs) 358 if (!info || !info->attrs)
@@ -353,11 +366,19 @@ static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
353 if (!ndp) 366 if (!ndp)
354 return -ENODEV; 367 return -ENODEV;
355 368
356 /* Clear any override */ 369 /* Reset any whitelists and disable multi mode */
357 spin_lock_irqsave(&ndp->lock, flags); 370 spin_lock_irqsave(&ndp->lock, flags);
358 ndp->force_package = NULL; 371 ndp->package_whitelist = UINT_MAX;
359 ndp->force_channel = NULL; 372 ndp->multi_package = false;
360 spin_unlock_irqrestore(&ndp->lock, flags); 373 spin_unlock_irqrestore(&ndp->lock, flags);
374
375 NCSI_FOR_EACH_PACKAGE(ndp, np) {
376 spin_lock_irqsave(&np->lock, flags);
377 np->multi_channel = false;
378 np->channel_whitelist = UINT_MAX;
379 np->preferred_channel = NULL;
380 spin_unlock_irqrestore(&np->lock, flags);
381 }
361 netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n"); 382 netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n");
362 383
363 /* Update channel configuration */ 384 /* Update channel configuration */
@@ -563,6 +584,138 @@ int ncsi_send_netlink_err(struct net_device *dev,
563 return nlmsg_unicast(net->genl_sock, skb, snd_portid); 584 return nlmsg_unicast(net->genl_sock, skb, snd_portid);
564} 585}
565 586
587static int ncsi_set_package_mask_nl(struct sk_buff *msg,
588 struct genl_info *info)
589{
590 struct ncsi_dev_priv *ndp;
591 unsigned long flags;
592 int rc;
593
594 if (!info || !info->attrs)
595 return -EINVAL;
596
597 if (!info->attrs[NCSI_ATTR_IFINDEX])
598 return -EINVAL;
599
600 if (!info->attrs[NCSI_ATTR_PACKAGE_MASK])
601 return -EINVAL;
602
603 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
604 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
605 if (!ndp)
606 return -ENODEV;
607
608 spin_lock_irqsave(&ndp->lock, flags);
609 if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) {
610 if (ndp->flags & NCSI_DEV_HWA) {
611 ndp->multi_package = true;
612 rc = 0;
613 } else {
614 netdev_err(ndp->ndev.dev,
615 "NCSI: Can't use multiple packages without HWA\n");
616 rc = -EPERM;
617 }
618 } else {
619 ndp->multi_package = false;
620 rc = 0;
621 }
622
623 if (!rc)
624 ndp->package_whitelist =
625 nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_MASK]);
626 spin_unlock_irqrestore(&ndp->lock, flags);
627
628 if (!rc) {
629 /* Update channel configuration */
630 if (!(ndp->flags & NCSI_DEV_RESET))
631 ncsi_reset_dev(&ndp->ndev);
632 }
633
634 return rc;
635}
636
637static int ncsi_set_channel_mask_nl(struct sk_buff *msg,
638 struct genl_info *info)
639{
640 struct ncsi_package *np, *package;
641 struct ncsi_channel *nc, *channel;
642 u32 package_id, channel_id;
643 struct ncsi_dev_priv *ndp;
644 unsigned long flags;
645
646 if (!info || !info->attrs)
647 return -EINVAL;
648
649 if (!info->attrs[NCSI_ATTR_IFINDEX])
650 return -EINVAL;
651
652 if (!info->attrs[NCSI_ATTR_PACKAGE_ID])
653 return -EINVAL;
654
655 if (!info->attrs[NCSI_ATTR_CHANNEL_MASK])
656 return -EINVAL;
657
658 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)),
659 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX]));
660 if (!ndp)
661 return -ENODEV;
662
663 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
664 package = NULL;
665 NCSI_FOR_EACH_PACKAGE(ndp, np)
666 if (np->id == package_id) {
667 package = np;
668 break;
669 }
670 if (!package)
671 return -ERANGE;
672
673 spin_lock_irqsave(&package->lock, flags);
674
675 channel = NULL;
676 if (info->attrs[NCSI_ATTR_CHANNEL_ID]) {
677 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
678 NCSI_FOR_EACH_CHANNEL(np, nc)
679 if (nc->id == channel_id) {
680 channel = nc;
681 break;
682 }
683 if (!channel) {
684 spin_unlock_irqrestore(&package->lock, flags);
685 return -ERANGE;
686 }
687 netdev_dbg(ndp->ndev.dev,
688 "NCSI: Channel %u set as preferred channel\n",
689 channel->id);
690 }
691
692 package->channel_whitelist =
693 nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_MASK]);
694 if (package->channel_whitelist == 0)
695 netdev_dbg(ndp->ndev.dev,
696 "NCSI: Package %u set to all channels disabled\n",
697 package->id);
698
699 package->preferred_channel = channel;
700
701 if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) {
702 package->multi_channel = true;
703 netdev_info(ndp->ndev.dev,
704 "NCSI: Multi-channel enabled on package %u\n",
705 package_id);
706 } else {
707 package->multi_channel = false;
708 }
709
710 spin_unlock_irqrestore(&package->lock, flags);
711
712 /* Update channel configuration */
713 if (!(ndp->flags & NCSI_DEV_RESET))
714 ncsi_reset_dev(&ndp->ndev);
715
716 return 0;
717}
718
566static const struct genl_ops ncsi_ops[] = { 719static const struct genl_ops ncsi_ops[] = {
567 { 720 {
568 .cmd = NCSI_CMD_PKG_INFO, 721 .cmd = NCSI_CMD_PKG_INFO,
@@ -589,6 +742,18 @@ static const struct genl_ops ncsi_ops[] = {
589 .doit = ncsi_send_cmd_nl, 742 .doit = ncsi_send_cmd_nl,
590 .flags = GENL_ADMIN_PERM, 743 .flags = GENL_ADMIN_PERM,
591 }, 744 },
745 {
746 .cmd = NCSI_CMD_SET_PACKAGE_MASK,
747 .policy = ncsi_genl_policy,
748 .doit = ncsi_set_package_mask_nl,
749 .flags = GENL_ADMIN_PERM,
750 },
751 {
752 .cmd = NCSI_CMD_SET_CHANNEL_MASK,
753 .policy = ncsi_genl_policy,
754 .doit = ncsi_set_channel_mask_nl,
755 .flags = GENL_ADMIN_PERM,
756 },
592}; 757};
593 758
594static struct genl_family ncsi_genl_family __ro_after_init = { 759static struct genl_family ncsi_genl_family __ro_after_init = {