162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * drivers/net/bond/bond_netlink.c - Netlink interface for bonding 462306a36Sopenharmony_ci * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us> 562306a36Sopenharmony_ci * Copyright (c) 2013 Scott Feldman <sfeldma@cumulusnetworks.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/netdevice.h> 1162306a36Sopenharmony_ci#include <linux/etherdevice.h> 1262306a36Sopenharmony_ci#include <linux/if_link.h> 1362306a36Sopenharmony_ci#include <linux/if_ether.h> 1462306a36Sopenharmony_ci#include <net/netlink.h> 1562306a36Sopenharmony_ci#include <net/rtnetlink.h> 1662306a36Sopenharmony_ci#include <net/bonding.h> 1762306a36Sopenharmony_ci#include <net/ipv6.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic size_t bond_get_slave_size(const struct net_device *bond_dev, 2062306a36Sopenharmony_ci const struct net_device *slave_dev) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci return nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_STATE */ 2362306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_MII_STATUS */ 2462306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_SLAVE_LINK_FAILURE_COUNT */ 2562306a36Sopenharmony_ci nla_total_size(MAX_ADDR_LEN) + /* IFLA_BOND_SLAVE_PERM_HWADDR */ 2662306a36Sopenharmony_ci nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_QUEUE_ID */ 2762306a36Sopenharmony_ci nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_AGGREGATOR_ID */ 2862306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE */ 2962306a36Sopenharmony_ci nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ 3062306a36Sopenharmony_ci nla_total_size(sizeof(s32)) + /* IFLA_BOND_SLAVE_PRIO */ 3162306a36Sopenharmony_ci 0; 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int bond_fill_slave_info(struct sk_buff *skb, 3562306a36Sopenharmony_ci const struct net_device *bond_dev, 3662306a36Sopenharmony_ci const struct net_device *slave_dev) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct slave *slave = bond_slave_get_rtnl(slave_dev); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_SLAVE_STATE, bond_slave_state(slave))) 4162306a36Sopenharmony_ci goto nla_put_failure; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_SLAVE_MII_STATUS, slave->link)) 4462306a36Sopenharmony_ci goto nla_put_failure; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, 4762306a36Sopenharmony_ci slave->link_failure_count)) 4862306a36Sopenharmony_ci goto nla_put_failure; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (nla_put(skb, IFLA_BOND_SLAVE_PERM_HWADDR, 5162306a36Sopenharmony_ci slave_dev->addr_len, slave->perm_hwaddr)) 5262306a36Sopenharmony_ci goto nla_put_failure; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_BOND_SLAVE_QUEUE_ID, slave->queue_id)) 5562306a36Sopenharmony_ci goto nla_put_failure; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (nla_put_s32(skb, IFLA_BOND_SLAVE_PRIO, slave->prio)) 5862306a36Sopenharmony_ci goto nla_put_failure; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { 6162306a36Sopenharmony_ci const struct aggregator *agg; 6262306a36Sopenharmony_ci const struct port *ad_port; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ad_port = &SLAVE_AD_INFO(slave)->port; 6562306a36Sopenharmony_ci agg = SLAVE_AD_INFO(slave)->port.aggregator; 6662306a36Sopenharmony_ci if (agg) { 6762306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, 6862306a36Sopenharmony_ci agg->aggregator_identifier)) 6962306a36Sopenharmony_ci goto nla_put_failure; 7062306a36Sopenharmony_ci if (nla_put_u8(skb, 7162306a36Sopenharmony_ci IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, 7262306a36Sopenharmony_ci ad_port->actor_oper_port_state)) 7362306a36Sopenharmony_ci goto nla_put_failure; 7462306a36Sopenharmony_ci if (nla_put_u16(skb, 7562306a36Sopenharmony_ci IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, 7662306a36Sopenharmony_ci ad_port->partner_oper.port_state)) 7762306a36Sopenharmony_ci goto nla_put_failure; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cinla_put_failure: 8462306a36Sopenharmony_ci return -EMSGSIZE; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* Limit the max delay range to 300s */ 8862306a36Sopenharmony_cistatic struct netlink_range_validation delay_range = { 8962306a36Sopenharmony_ci .max = 300000, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { 9362306a36Sopenharmony_ci [IFLA_BOND_MODE] = { .type = NLA_U8 }, 9462306a36Sopenharmony_ci [IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 }, 9562306a36Sopenharmony_ci [IFLA_BOND_MIIMON] = { .type = NLA_U32 }, 9662306a36Sopenharmony_ci [IFLA_BOND_UPDELAY] = { .type = NLA_U32 }, 9762306a36Sopenharmony_ci [IFLA_BOND_DOWNDELAY] = { .type = NLA_U32 }, 9862306a36Sopenharmony_ci [IFLA_BOND_USE_CARRIER] = { .type = NLA_U8 }, 9962306a36Sopenharmony_ci [IFLA_BOND_ARP_INTERVAL] = { .type = NLA_U32 }, 10062306a36Sopenharmony_ci [IFLA_BOND_ARP_IP_TARGET] = { .type = NLA_NESTED }, 10162306a36Sopenharmony_ci [IFLA_BOND_ARP_VALIDATE] = { .type = NLA_U32 }, 10262306a36Sopenharmony_ci [IFLA_BOND_ARP_ALL_TARGETS] = { .type = NLA_U32 }, 10362306a36Sopenharmony_ci [IFLA_BOND_PRIMARY] = { .type = NLA_U32 }, 10462306a36Sopenharmony_ci [IFLA_BOND_PRIMARY_RESELECT] = { .type = NLA_U8 }, 10562306a36Sopenharmony_ci [IFLA_BOND_FAIL_OVER_MAC] = { .type = NLA_U8 }, 10662306a36Sopenharmony_ci [IFLA_BOND_XMIT_HASH_POLICY] = { .type = NLA_U8 }, 10762306a36Sopenharmony_ci [IFLA_BOND_RESEND_IGMP] = { .type = NLA_U32 }, 10862306a36Sopenharmony_ci [IFLA_BOND_NUM_PEER_NOTIF] = { .type = NLA_U8 }, 10962306a36Sopenharmony_ci [IFLA_BOND_ALL_SLAVES_ACTIVE] = { .type = NLA_U8 }, 11062306a36Sopenharmony_ci [IFLA_BOND_MIN_LINKS] = { .type = NLA_U32 }, 11162306a36Sopenharmony_ci [IFLA_BOND_LP_INTERVAL] = { .type = NLA_U32 }, 11262306a36Sopenharmony_ci [IFLA_BOND_PACKETS_PER_SLAVE] = { .type = NLA_U32 }, 11362306a36Sopenharmony_ci [IFLA_BOND_AD_LACP_ACTIVE] = { .type = NLA_U8 }, 11462306a36Sopenharmony_ci [IFLA_BOND_AD_LACP_RATE] = { .type = NLA_U8 }, 11562306a36Sopenharmony_ci [IFLA_BOND_AD_SELECT] = { .type = NLA_U8 }, 11662306a36Sopenharmony_ci [IFLA_BOND_AD_INFO] = { .type = NLA_NESTED }, 11762306a36Sopenharmony_ci [IFLA_BOND_AD_ACTOR_SYS_PRIO] = { .type = NLA_U16 }, 11862306a36Sopenharmony_ci [IFLA_BOND_AD_USER_PORT_KEY] = { .type = NLA_U16 }, 11962306a36Sopenharmony_ci [IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NLA_BINARY, 12062306a36Sopenharmony_ci .len = ETH_ALEN }, 12162306a36Sopenharmony_ci [IFLA_BOND_TLB_DYNAMIC_LB] = { .type = NLA_U8 }, 12262306a36Sopenharmony_ci [IFLA_BOND_PEER_NOTIF_DELAY] = NLA_POLICY_FULL_RANGE(NLA_U32, &delay_range), 12362306a36Sopenharmony_ci [IFLA_BOND_MISSED_MAX] = { .type = NLA_U8 }, 12462306a36Sopenharmony_ci [IFLA_BOND_NS_IP6_TARGET] = { .type = NLA_NESTED }, 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { 12862306a36Sopenharmony_ci [IFLA_BOND_SLAVE_QUEUE_ID] = { .type = NLA_U16 }, 12962306a36Sopenharmony_ci [IFLA_BOND_SLAVE_PRIO] = { .type = NLA_S32 }, 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic int bond_validate(struct nlattr *tb[], struct nlattr *data[], 13362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci if (tb[IFLA_ADDRESS]) { 13662306a36Sopenharmony_ci if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 13762306a36Sopenharmony_ci return -EINVAL; 13862306a36Sopenharmony_ci if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 13962306a36Sopenharmony_ci return -EADDRNOTAVAIL; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int bond_slave_changelink(struct net_device *bond_dev, 14562306a36Sopenharmony_ci struct net_device *slave_dev, 14662306a36Sopenharmony_ci struct nlattr *tb[], struct nlattr *data[], 14762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 15062306a36Sopenharmony_ci struct bond_opt_value newval; 15162306a36Sopenharmony_ci int err; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (!data) 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (data[IFLA_BOND_SLAVE_QUEUE_ID]) { 15762306a36Sopenharmony_ci u16 queue_id = nla_get_u16(data[IFLA_BOND_SLAVE_QUEUE_ID]); 15862306a36Sopenharmony_ci char queue_id_str[IFNAMSIZ + 7]; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* queue_id option setting expects slave_name:queue_id */ 16162306a36Sopenharmony_ci snprintf(queue_id_str, sizeof(queue_id_str), "%s:%u\n", 16262306a36Sopenharmony_ci slave_dev->name, queue_id); 16362306a36Sopenharmony_ci bond_opt_initstr(&newval, queue_id_str); 16462306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_QUEUE_ID, &newval, 16562306a36Sopenharmony_ci data[IFLA_BOND_SLAVE_QUEUE_ID], extack); 16662306a36Sopenharmony_ci if (err) 16762306a36Sopenharmony_ci return err; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (data[IFLA_BOND_SLAVE_PRIO]) { 17162306a36Sopenharmony_ci int prio = nla_get_s32(data[IFLA_BOND_SLAVE_PRIO]); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci bond_opt_slave_initval(&newval, &slave_dev, prio); 17462306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_PRIO, &newval, 17562306a36Sopenharmony_ci data[IFLA_BOND_SLAVE_PRIO], extack); 17662306a36Sopenharmony_ci if (err) 17762306a36Sopenharmony_ci return err; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[], 18462306a36Sopenharmony_ci struct nlattr *data[], 18562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 18862306a36Sopenharmony_ci struct bond_opt_value newval; 18962306a36Sopenharmony_ci int miimon = 0; 19062306a36Sopenharmony_ci int err; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (!data) 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (data[IFLA_BOND_MODE]) { 19662306a36Sopenharmony_ci int mode = nla_get_u8(data[IFLA_BOND_MODE]); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci bond_opt_initval(&newval, mode); 19962306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_MODE, &newval, 20062306a36Sopenharmony_ci data[IFLA_BOND_MODE], extack); 20162306a36Sopenharmony_ci if (err) 20262306a36Sopenharmony_ci return err; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci if (data[IFLA_BOND_ACTIVE_SLAVE]) { 20562306a36Sopenharmony_ci int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]); 20662306a36Sopenharmony_ci struct net_device *slave_dev; 20762306a36Sopenharmony_ci char *active_slave = ""; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (ifindex != 0) { 21062306a36Sopenharmony_ci slave_dev = __dev_get_by_index(dev_net(bond_dev), 21162306a36Sopenharmony_ci ifindex); 21262306a36Sopenharmony_ci if (!slave_dev) 21362306a36Sopenharmony_ci return -ENODEV; 21462306a36Sopenharmony_ci active_slave = slave_dev->name; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci bond_opt_initstr(&newval, active_slave); 21762306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval, 21862306a36Sopenharmony_ci data[IFLA_BOND_ACTIVE_SLAVE], extack); 21962306a36Sopenharmony_ci if (err) 22062306a36Sopenharmony_ci return err; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci if (data[IFLA_BOND_MIIMON]) { 22362306a36Sopenharmony_ci miimon = nla_get_u32(data[IFLA_BOND_MIIMON]); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci bond_opt_initval(&newval, miimon); 22662306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_MIIMON, &newval, 22762306a36Sopenharmony_ci data[IFLA_BOND_MIIMON], extack); 22862306a36Sopenharmony_ci if (err) 22962306a36Sopenharmony_ci return err; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci if (data[IFLA_BOND_UPDELAY]) { 23262306a36Sopenharmony_ci int updelay = nla_get_u32(data[IFLA_BOND_UPDELAY]); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci bond_opt_initval(&newval, updelay); 23562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_UPDELAY, &newval, 23662306a36Sopenharmony_ci data[IFLA_BOND_UPDELAY], extack); 23762306a36Sopenharmony_ci if (err) 23862306a36Sopenharmony_ci return err; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci if (data[IFLA_BOND_DOWNDELAY]) { 24162306a36Sopenharmony_ci int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci bond_opt_initval(&newval, downdelay); 24462306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_DOWNDELAY, &newval, 24562306a36Sopenharmony_ci data[IFLA_BOND_DOWNDELAY], extack); 24662306a36Sopenharmony_ci if (err) 24762306a36Sopenharmony_ci return err; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci if (data[IFLA_BOND_PEER_NOTIF_DELAY]) { 25062306a36Sopenharmony_ci int delay = nla_get_u32(data[IFLA_BOND_PEER_NOTIF_DELAY]); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci bond_opt_initval(&newval, delay); 25362306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_PEER_NOTIF_DELAY, &newval, 25462306a36Sopenharmony_ci data[IFLA_BOND_PEER_NOTIF_DELAY], extack); 25562306a36Sopenharmony_ci if (err) 25662306a36Sopenharmony_ci return err; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci if (data[IFLA_BOND_USE_CARRIER]) { 25962306a36Sopenharmony_ci int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci bond_opt_initval(&newval, use_carrier); 26262306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_USE_CARRIER, &newval, 26362306a36Sopenharmony_ci data[IFLA_BOND_USE_CARRIER], extack); 26462306a36Sopenharmony_ci if (err) 26562306a36Sopenharmony_ci return err; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci if (data[IFLA_BOND_ARP_INTERVAL]) { 26862306a36Sopenharmony_ci int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (arp_interval && miimon) { 27162306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_BOND_ARP_INTERVAL], 27262306a36Sopenharmony_ci "ARP monitoring cannot be used with MII monitoring"); 27362306a36Sopenharmony_ci return -EINVAL; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci bond_opt_initval(&newval, arp_interval); 27762306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_ARP_INTERVAL, &newval, 27862306a36Sopenharmony_ci data[IFLA_BOND_ARP_INTERVAL], extack); 27962306a36Sopenharmony_ci if (err) 28062306a36Sopenharmony_ci return err; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci if (data[IFLA_BOND_ARP_IP_TARGET]) { 28362306a36Sopenharmony_ci struct nlattr *attr; 28462306a36Sopenharmony_ci int i = 0, rem; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci bond_option_arp_ip_targets_clear(bond); 28762306a36Sopenharmony_ci nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) { 28862306a36Sopenharmony_ci __be32 target; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (nla_len(attr) < sizeof(target)) 29162306a36Sopenharmony_ci return -EINVAL; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci target = nla_get_be32(attr); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci bond_opt_initval(&newval, (__force u64)target); 29662306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS, 29762306a36Sopenharmony_ci &newval, 29862306a36Sopenharmony_ci data[IFLA_BOND_ARP_IP_TARGET], 29962306a36Sopenharmony_ci extack); 30062306a36Sopenharmony_ci if (err) 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci i++; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci if (i == 0 && bond->params.arp_interval) 30562306a36Sopenharmony_ci netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n"); 30662306a36Sopenharmony_ci if (err) 30762306a36Sopenharmony_ci return err; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 31062306a36Sopenharmony_ci if (data[IFLA_BOND_NS_IP6_TARGET]) { 31162306a36Sopenharmony_ci struct nlattr *attr; 31262306a36Sopenharmony_ci int i = 0, rem; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci bond_option_ns_ip6_targets_clear(bond); 31562306a36Sopenharmony_ci nla_for_each_nested(attr, data[IFLA_BOND_NS_IP6_TARGET], rem) { 31662306a36Sopenharmony_ci struct in6_addr addr6; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (nla_len(attr) < sizeof(addr6)) { 31962306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "Invalid IPv6 address"); 32062306a36Sopenharmony_ci return -EINVAL; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci addr6 = nla_get_in6_addr(attr); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci bond_opt_initextra(&newval, &addr6, sizeof(addr6)); 32662306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_NS_TARGETS, 32762306a36Sopenharmony_ci &newval, 32862306a36Sopenharmony_ci data[IFLA_BOND_NS_IP6_TARGET], 32962306a36Sopenharmony_ci extack); 33062306a36Sopenharmony_ci if (err) 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci i++; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci if (i == 0 && bond->params.arp_interval) 33562306a36Sopenharmony_ci netdev_warn(bond->dev, "Removing last ns target with arp_interval on\n"); 33662306a36Sopenharmony_ci if (err) 33762306a36Sopenharmony_ci return err; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci#endif 34062306a36Sopenharmony_ci if (data[IFLA_BOND_ARP_VALIDATE]) { 34162306a36Sopenharmony_ci int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (arp_validate && miimon) { 34462306a36Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, data[IFLA_BOND_ARP_INTERVAL], 34562306a36Sopenharmony_ci "ARP validating cannot be used with MII monitoring"); 34662306a36Sopenharmony_ci return -EINVAL; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci bond_opt_initval(&newval, arp_validate); 35062306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_ARP_VALIDATE, &newval, 35162306a36Sopenharmony_ci data[IFLA_BOND_ARP_VALIDATE], extack); 35262306a36Sopenharmony_ci if (err) 35362306a36Sopenharmony_ci return err; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci if (data[IFLA_BOND_ARP_ALL_TARGETS]) { 35662306a36Sopenharmony_ci int arp_all_targets = 35762306a36Sopenharmony_ci nla_get_u32(data[IFLA_BOND_ARP_ALL_TARGETS]); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci bond_opt_initval(&newval, arp_all_targets); 36062306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_ARP_ALL_TARGETS, &newval, 36162306a36Sopenharmony_ci data[IFLA_BOND_ARP_ALL_TARGETS], extack); 36262306a36Sopenharmony_ci if (err) 36362306a36Sopenharmony_ci return err; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci if (data[IFLA_BOND_PRIMARY]) { 36662306a36Sopenharmony_ci int ifindex = nla_get_u32(data[IFLA_BOND_PRIMARY]); 36762306a36Sopenharmony_ci struct net_device *dev; 36862306a36Sopenharmony_ci char *primary = ""; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci dev = __dev_get_by_index(dev_net(bond_dev), ifindex); 37162306a36Sopenharmony_ci if (dev) 37262306a36Sopenharmony_ci primary = dev->name; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci bond_opt_initstr(&newval, primary); 37562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_PRIMARY, &newval, 37662306a36Sopenharmony_ci data[IFLA_BOND_PRIMARY], extack); 37762306a36Sopenharmony_ci if (err) 37862306a36Sopenharmony_ci return err; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci if (data[IFLA_BOND_PRIMARY_RESELECT]) { 38162306a36Sopenharmony_ci int primary_reselect = 38262306a36Sopenharmony_ci nla_get_u8(data[IFLA_BOND_PRIMARY_RESELECT]); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci bond_opt_initval(&newval, primary_reselect); 38562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_PRIMARY_RESELECT, &newval, 38662306a36Sopenharmony_ci data[IFLA_BOND_PRIMARY_RESELECT], extack); 38762306a36Sopenharmony_ci if (err) 38862306a36Sopenharmony_ci return err; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci if (data[IFLA_BOND_FAIL_OVER_MAC]) { 39162306a36Sopenharmony_ci int fail_over_mac = 39262306a36Sopenharmony_ci nla_get_u8(data[IFLA_BOND_FAIL_OVER_MAC]); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci bond_opt_initval(&newval, fail_over_mac); 39562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_FAIL_OVER_MAC, &newval, 39662306a36Sopenharmony_ci data[IFLA_BOND_FAIL_OVER_MAC], extack); 39762306a36Sopenharmony_ci if (err) 39862306a36Sopenharmony_ci return err; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci if (data[IFLA_BOND_XMIT_HASH_POLICY]) { 40162306a36Sopenharmony_ci int xmit_hash_policy = 40262306a36Sopenharmony_ci nla_get_u8(data[IFLA_BOND_XMIT_HASH_POLICY]); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci bond_opt_initval(&newval, xmit_hash_policy); 40562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_XMIT_HASH, &newval, 40662306a36Sopenharmony_ci data[IFLA_BOND_XMIT_HASH_POLICY], extack); 40762306a36Sopenharmony_ci if (err) 40862306a36Sopenharmony_ci return err; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci if (data[IFLA_BOND_RESEND_IGMP]) { 41162306a36Sopenharmony_ci int resend_igmp = 41262306a36Sopenharmony_ci nla_get_u32(data[IFLA_BOND_RESEND_IGMP]); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci bond_opt_initval(&newval, resend_igmp); 41562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_RESEND_IGMP, &newval, 41662306a36Sopenharmony_ci data[IFLA_BOND_RESEND_IGMP], extack); 41762306a36Sopenharmony_ci if (err) 41862306a36Sopenharmony_ci return err; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci if (data[IFLA_BOND_NUM_PEER_NOTIF]) { 42162306a36Sopenharmony_ci int num_peer_notif = 42262306a36Sopenharmony_ci nla_get_u8(data[IFLA_BOND_NUM_PEER_NOTIF]); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci bond_opt_initval(&newval, num_peer_notif); 42562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_NUM_PEER_NOTIF, &newval, 42662306a36Sopenharmony_ci data[IFLA_BOND_NUM_PEER_NOTIF], extack); 42762306a36Sopenharmony_ci if (err) 42862306a36Sopenharmony_ci return err; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci if (data[IFLA_BOND_ALL_SLAVES_ACTIVE]) { 43162306a36Sopenharmony_ci int all_slaves_active = 43262306a36Sopenharmony_ci nla_get_u8(data[IFLA_BOND_ALL_SLAVES_ACTIVE]); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci bond_opt_initval(&newval, all_slaves_active); 43562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_ALL_SLAVES_ACTIVE, &newval, 43662306a36Sopenharmony_ci data[IFLA_BOND_ALL_SLAVES_ACTIVE], extack); 43762306a36Sopenharmony_ci if (err) 43862306a36Sopenharmony_ci return err; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci if (data[IFLA_BOND_MIN_LINKS]) { 44162306a36Sopenharmony_ci int min_links = 44262306a36Sopenharmony_ci nla_get_u32(data[IFLA_BOND_MIN_LINKS]); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci bond_opt_initval(&newval, min_links); 44562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_MINLINKS, &newval, 44662306a36Sopenharmony_ci data[IFLA_BOND_MIN_LINKS], extack); 44762306a36Sopenharmony_ci if (err) 44862306a36Sopenharmony_ci return err; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci if (data[IFLA_BOND_LP_INTERVAL]) { 45162306a36Sopenharmony_ci int lp_interval = 45262306a36Sopenharmony_ci nla_get_u32(data[IFLA_BOND_LP_INTERVAL]); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci bond_opt_initval(&newval, lp_interval); 45562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_LP_INTERVAL, &newval, 45662306a36Sopenharmony_ci data[IFLA_BOND_LP_INTERVAL], extack); 45762306a36Sopenharmony_ci if (err) 45862306a36Sopenharmony_ci return err; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci if (data[IFLA_BOND_PACKETS_PER_SLAVE]) { 46162306a36Sopenharmony_ci int packets_per_slave = 46262306a36Sopenharmony_ci nla_get_u32(data[IFLA_BOND_PACKETS_PER_SLAVE]); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci bond_opt_initval(&newval, packets_per_slave); 46562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_PACKETS_PER_SLAVE, &newval, 46662306a36Sopenharmony_ci data[IFLA_BOND_PACKETS_PER_SLAVE], extack); 46762306a36Sopenharmony_ci if (err) 46862306a36Sopenharmony_ci return err; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (data[IFLA_BOND_AD_LACP_ACTIVE]) { 47262306a36Sopenharmony_ci int lacp_active = nla_get_u8(data[IFLA_BOND_AD_LACP_ACTIVE]); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci bond_opt_initval(&newval, lacp_active); 47562306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_LACP_ACTIVE, &newval, 47662306a36Sopenharmony_ci data[IFLA_BOND_AD_LACP_ACTIVE], extack); 47762306a36Sopenharmony_ci if (err) 47862306a36Sopenharmony_ci return err; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (data[IFLA_BOND_AD_LACP_RATE]) { 48262306a36Sopenharmony_ci int lacp_rate = 48362306a36Sopenharmony_ci nla_get_u8(data[IFLA_BOND_AD_LACP_RATE]); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci bond_opt_initval(&newval, lacp_rate); 48662306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_LACP_RATE, &newval, 48762306a36Sopenharmony_ci data[IFLA_BOND_AD_LACP_RATE], extack); 48862306a36Sopenharmony_ci if (err) 48962306a36Sopenharmony_ci return err; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci if (data[IFLA_BOND_AD_SELECT]) { 49262306a36Sopenharmony_ci int ad_select = 49362306a36Sopenharmony_ci nla_get_u8(data[IFLA_BOND_AD_SELECT]); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci bond_opt_initval(&newval, ad_select); 49662306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_AD_SELECT, &newval, 49762306a36Sopenharmony_ci data[IFLA_BOND_AD_SELECT], extack); 49862306a36Sopenharmony_ci if (err) 49962306a36Sopenharmony_ci return err; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci if (data[IFLA_BOND_AD_ACTOR_SYS_PRIO]) { 50262306a36Sopenharmony_ci int actor_sys_prio = 50362306a36Sopenharmony_ci nla_get_u16(data[IFLA_BOND_AD_ACTOR_SYS_PRIO]); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci bond_opt_initval(&newval, actor_sys_prio); 50662306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval, 50762306a36Sopenharmony_ci data[IFLA_BOND_AD_ACTOR_SYS_PRIO], extack); 50862306a36Sopenharmony_ci if (err) 50962306a36Sopenharmony_ci return err; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci if (data[IFLA_BOND_AD_USER_PORT_KEY]) { 51262306a36Sopenharmony_ci int port_key = 51362306a36Sopenharmony_ci nla_get_u16(data[IFLA_BOND_AD_USER_PORT_KEY]); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci bond_opt_initval(&newval, port_key); 51662306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval, 51762306a36Sopenharmony_ci data[IFLA_BOND_AD_USER_PORT_KEY], extack); 51862306a36Sopenharmony_ci if (err) 51962306a36Sopenharmony_ci return err; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci if (data[IFLA_BOND_AD_ACTOR_SYSTEM]) { 52262306a36Sopenharmony_ci if (nla_len(data[IFLA_BOND_AD_ACTOR_SYSTEM]) != ETH_ALEN) 52362306a36Sopenharmony_ci return -EINVAL; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci bond_opt_initval(&newval, 52662306a36Sopenharmony_ci nla_get_u64(data[IFLA_BOND_AD_ACTOR_SYSTEM])); 52762306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval, 52862306a36Sopenharmony_ci data[IFLA_BOND_AD_ACTOR_SYSTEM], extack); 52962306a36Sopenharmony_ci if (err) 53062306a36Sopenharmony_ci return err; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci if (data[IFLA_BOND_TLB_DYNAMIC_LB]) { 53362306a36Sopenharmony_ci int dynamic_lb = nla_get_u8(data[IFLA_BOND_TLB_DYNAMIC_LB]); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci bond_opt_initval(&newval, dynamic_lb); 53662306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_TLB_DYNAMIC_LB, &newval, 53762306a36Sopenharmony_ci data[IFLA_BOND_TLB_DYNAMIC_LB], extack); 53862306a36Sopenharmony_ci if (err) 53962306a36Sopenharmony_ci return err; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (data[IFLA_BOND_MISSED_MAX]) { 54362306a36Sopenharmony_ci int missed_max = nla_get_u8(data[IFLA_BOND_MISSED_MAX]); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci bond_opt_initval(&newval, missed_max); 54662306a36Sopenharmony_ci err = __bond_opt_set(bond, BOND_OPT_MISSED_MAX, &newval, 54762306a36Sopenharmony_ci data[IFLA_BOND_MISSED_MAX], extack); 54862306a36Sopenharmony_ci if (err) 54962306a36Sopenharmony_ci return err; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return 0; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic int bond_newlink(struct net *src_net, struct net_device *bond_dev, 55662306a36Sopenharmony_ci struct nlattr *tb[], struct nlattr *data[], 55762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci int err; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci err = bond_changelink(bond_dev, tb, data, extack); 56262306a36Sopenharmony_ci if (err < 0) 56362306a36Sopenharmony_ci return err; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci err = register_netdevice(bond_dev); 56662306a36Sopenharmony_ci if (!err) { 56762306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci netif_carrier_off(bond_dev); 57062306a36Sopenharmony_ci bond_work_init_all(bond); 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci return err; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic size_t bond_get_size(const struct net_device *bond_dev) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci return nla_total_size(sizeof(u8)) + /* IFLA_BOND_MODE */ 57962306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_ACTIVE_SLAVE */ 58062306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_MIIMON */ 58162306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_UPDELAY */ 58262306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_DOWNDELAY */ 58362306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_USE_CARRIER */ 58462306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_INTERVAL */ 58562306a36Sopenharmony_ci /* IFLA_BOND_ARP_IP_TARGET */ 58662306a36Sopenharmony_ci nla_total_size(sizeof(struct nlattr)) + 58762306a36Sopenharmony_ci nla_total_size(sizeof(u32)) * BOND_MAX_ARP_TARGETS + 58862306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_VALIDATE */ 58962306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_ALL_TARGETS */ 59062306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_PRIMARY */ 59162306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_PRIMARY_RESELECT */ 59262306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_FAIL_OVER_MAC */ 59362306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_XMIT_HASH_POLICY */ 59462306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_RESEND_IGMP */ 59562306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_NUM_PEER_NOTIF */ 59662306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_ALL_SLAVES_ACTIVE */ 59762306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_MIN_LINKS */ 59862306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_LP_INTERVAL */ 59962306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_PACKETS_PER_SLAVE */ 60062306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_AD_LACP_ACTIVE */ 60162306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_AD_LACP_RATE */ 60262306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_AD_SELECT */ 60362306a36Sopenharmony_ci nla_total_size(sizeof(struct nlattr)) + /* IFLA_BOND_AD_INFO */ 60462306a36Sopenharmony_ci nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_AGGREGATOR */ 60562306a36Sopenharmony_ci nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_NUM_PORTS */ 60662306a36Sopenharmony_ci nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_ACTOR_KEY */ 60762306a36Sopenharmony_ci nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_PARTNER_KEY*/ 60862306a36Sopenharmony_ci nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_INFO_PARTNER_MAC*/ 60962306a36Sopenharmony_ci nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_ACTOR_SYS_PRIO */ 61062306a36Sopenharmony_ci nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_USER_PORT_KEY */ 61162306a36Sopenharmony_ci nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_ACTOR_SYSTEM */ 61262306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_TLB_DYNAMIC_LB */ 61362306a36Sopenharmony_ci nla_total_size(sizeof(u32)) + /* IFLA_BOND_PEER_NOTIF_DELAY */ 61462306a36Sopenharmony_ci nla_total_size(sizeof(u8)) + /* IFLA_BOND_MISSED_MAX */ 61562306a36Sopenharmony_ci /* IFLA_BOND_NS_IP6_TARGET */ 61662306a36Sopenharmony_ci nla_total_size(sizeof(struct nlattr)) + 61762306a36Sopenharmony_ci nla_total_size(sizeof(struct in6_addr)) * BOND_MAX_NS_TARGETS + 61862306a36Sopenharmony_ci 0; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic int bond_option_active_slave_get_ifindex(struct bonding *bond) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci const struct net_device *slave; 62462306a36Sopenharmony_ci int ifindex; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci rcu_read_lock(); 62762306a36Sopenharmony_ci slave = bond_option_active_slave_get_rcu(bond); 62862306a36Sopenharmony_ci ifindex = slave ? slave->ifindex : 0; 62962306a36Sopenharmony_ci rcu_read_unlock(); 63062306a36Sopenharmony_ci return ifindex; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic int bond_fill_info(struct sk_buff *skb, 63462306a36Sopenharmony_ci const struct net_device *bond_dev) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 63762306a36Sopenharmony_ci unsigned int packets_per_slave; 63862306a36Sopenharmony_ci int ifindex, i, targets_added; 63962306a36Sopenharmony_ci struct nlattr *targets; 64062306a36Sopenharmony_ci struct slave *primary; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_MODE, BOND_MODE(bond))) 64362306a36Sopenharmony_ci goto nla_put_failure; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci ifindex = bond_option_active_slave_get_ifindex(bond); 64662306a36Sopenharmony_ci if (ifindex && nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, ifindex)) 64762306a36Sopenharmony_ci goto nla_put_failure; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_MIIMON, bond->params.miimon)) 65062306a36Sopenharmony_ci goto nla_put_failure; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_UPDELAY, 65362306a36Sopenharmony_ci bond->params.updelay * bond->params.miimon)) 65462306a36Sopenharmony_ci goto nla_put_failure; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_DOWNDELAY, 65762306a36Sopenharmony_ci bond->params.downdelay * bond->params.miimon)) 65862306a36Sopenharmony_ci goto nla_put_failure; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_PEER_NOTIF_DELAY, 66162306a36Sopenharmony_ci bond->params.peer_notif_delay * bond->params.miimon)) 66262306a36Sopenharmony_ci goto nla_put_failure; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_USE_CARRIER, bond->params.use_carrier)) 66562306a36Sopenharmony_ci goto nla_put_failure; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_ARP_INTERVAL, bond->params.arp_interval)) 66862306a36Sopenharmony_ci goto nla_put_failure; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci targets = nla_nest_start_noflag(skb, IFLA_BOND_ARP_IP_TARGET); 67162306a36Sopenharmony_ci if (!targets) 67262306a36Sopenharmony_ci goto nla_put_failure; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci targets_added = 0; 67562306a36Sopenharmony_ci for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { 67662306a36Sopenharmony_ci if (bond->params.arp_targets[i]) { 67762306a36Sopenharmony_ci if (nla_put_be32(skb, i, bond->params.arp_targets[i])) 67862306a36Sopenharmony_ci goto nla_put_failure; 67962306a36Sopenharmony_ci targets_added = 1; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (targets_added) 68462306a36Sopenharmony_ci nla_nest_end(skb, targets); 68562306a36Sopenharmony_ci else 68662306a36Sopenharmony_ci nla_nest_cancel(skb, targets); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_ARP_VALIDATE, bond->params.arp_validate)) 68962306a36Sopenharmony_ci goto nla_put_failure; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_ARP_ALL_TARGETS, 69262306a36Sopenharmony_ci bond->params.arp_all_targets)) 69362306a36Sopenharmony_ci goto nla_put_failure; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 69662306a36Sopenharmony_ci targets = nla_nest_start(skb, IFLA_BOND_NS_IP6_TARGET); 69762306a36Sopenharmony_ci if (!targets) 69862306a36Sopenharmony_ci goto nla_put_failure; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci targets_added = 0; 70162306a36Sopenharmony_ci for (i = 0; i < BOND_MAX_NS_TARGETS; i++) { 70262306a36Sopenharmony_ci if (!ipv6_addr_any(&bond->params.ns_targets[i])) { 70362306a36Sopenharmony_ci if (nla_put_in6_addr(skb, i, &bond->params.ns_targets[i])) 70462306a36Sopenharmony_ci goto nla_put_failure; 70562306a36Sopenharmony_ci targets_added = 1; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (targets_added) 71062306a36Sopenharmony_ci nla_nest_end(skb, targets); 71162306a36Sopenharmony_ci else 71262306a36Sopenharmony_ci nla_nest_cancel(skb, targets); 71362306a36Sopenharmony_ci#endif 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci primary = rtnl_dereference(bond->primary_slave); 71662306a36Sopenharmony_ci if (primary && 71762306a36Sopenharmony_ci nla_put_u32(skb, IFLA_BOND_PRIMARY, primary->dev->ifindex)) 71862306a36Sopenharmony_ci goto nla_put_failure; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_PRIMARY_RESELECT, 72162306a36Sopenharmony_ci bond->params.primary_reselect)) 72262306a36Sopenharmony_ci goto nla_put_failure; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_FAIL_OVER_MAC, 72562306a36Sopenharmony_ci bond->params.fail_over_mac)) 72662306a36Sopenharmony_ci goto nla_put_failure; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_XMIT_HASH_POLICY, 72962306a36Sopenharmony_ci bond->params.xmit_policy)) 73062306a36Sopenharmony_ci goto nla_put_failure; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_RESEND_IGMP, 73362306a36Sopenharmony_ci bond->params.resend_igmp)) 73462306a36Sopenharmony_ci goto nla_put_failure; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_NUM_PEER_NOTIF, 73762306a36Sopenharmony_ci bond->params.num_peer_notif)) 73862306a36Sopenharmony_ci goto nla_put_failure; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_ALL_SLAVES_ACTIVE, 74162306a36Sopenharmony_ci bond->params.all_slaves_active)) 74262306a36Sopenharmony_ci goto nla_put_failure; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_MIN_LINKS, 74562306a36Sopenharmony_ci bond->params.min_links)) 74662306a36Sopenharmony_ci goto nla_put_failure; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_LP_INTERVAL, 74962306a36Sopenharmony_ci bond->params.lp_interval)) 75062306a36Sopenharmony_ci goto nla_put_failure; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci packets_per_slave = bond->params.packets_per_slave; 75362306a36Sopenharmony_ci if (nla_put_u32(skb, IFLA_BOND_PACKETS_PER_SLAVE, 75462306a36Sopenharmony_ci packets_per_slave)) 75562306a36Sopenharmony_ci goto nla_put_failure; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_AD_LACP_ACTIVE, 75862306a36Sopenharmony_ci bond->params.lacp_active)) 75962306a36Sopenharmony_ci goto nla_put_failure; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_AD_LACP_RATE, 76262306a36Sopenharmony_ci bond->params.lacp_fast)) 76362306a36Sopenharmony_ci goto nla_put_failure; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_AD_SELECT, 76662306a36Sopenharmony_ci bond->params.ad_select)) 76762306a36Sopenharmony_ci goto nla_put_failure; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_TLB_DYNAMIC_LB, 77062306a36Sopenharmony_ci bond->params.tlb_dynamic_lb)) 77162306a36Sopenharmony_ci goto nla_put_failure; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (nla_put_u8(skb, IFLA_BOND_MISSED_MAX, 77462306a36Sopenharmony_ci bond->params.missed_max)) 77562306a36Sopenharmony_ci goto nla_put_failure; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) { 77862306a36Sopenharmony_ci struct ad_info info; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (capable(CAP_NET_ADMIN)) { 78162306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_BOND_AD_ACTOR_SYS_PRIO, 78262306a36Sopenharmony_ci bond->params.ad_actor_sys_prio)) 78362306a36Sopenharmony_ci goto nla_put_failure; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_BOND_AD_USER_PORT_KEY, 78662306a36Sopenharmony_ci bond->params.ad_user_port_key)) 78762306a36Sopenharmony_ci goto nla_put_failure; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (nla_put(skb, IFLA_BOND_AD_ACTOR_SYSTEM, 79062306a36Sopenharmony_ci ETH_ALEN, &bond->params.ad_actor_system)) 79162306a36Sopenharmony_ci goto nla_put_failure; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci if (!bond_3ad_get_active_agg_info(bond, &info)) { 79462306a36Sopenharmony_ci struct nlattr *nest; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci nest = nla_nest_start_noflag(skb, IFLA_BOND_AD_INFO); 79762306a36Sopenharmony_ci if (!nest) 79862306a36Sopenharmony_ci goto nla_put_failure; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_BOND_AD_INFO_AGGREGATOR, 80162306a36Sopenharmony_ci info.aggregator_id)) 80262306a36Sopenharmony_ci goto nla_put_failure; 80362306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_BOND_AD_INFO_NUM_PORTS, 80462306a36Sopenharmony_ci info.ports)) 80562306a36Sopenharmony_ci goto nla_put_failure; 80662306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_BOND_AD_INFO_ACTOR_KEY, 80762306a36Sopenharmony_ci info.actor_key)) 80862306a36Sopenharmony_ci goto nla_put_failure; 80962306a36Sopenharmony_ci if (nla_put_u16(skb, IFLA_BOND_AD_INFO_PARTNER_KEY, 81062306a36Sopenharmony_ci info.partner_key)) 81162306a36Sopenharmony_ci goto nla_put_failure; 81262306a36Sopenharmony_ci if (nla_put(skb, IFLA_BOND_AD_INFO_PARTNER_MAC, 81362306a36Sopenharmony_ci sizeof(info.partner_system), 81462306a36Sopenharmony_ci &info.partner_system)) 81562306a36Sopenharmony_ci goto nla_put_failure; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci nla_nest_end(skb, nest); 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci return 0; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cinla_put_failure: 82462306a36Sopenharmony_ci return -EMSGSIZE; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic size_t bond_get_linkxstats_size(const struct net_device *dev, int attr) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci switch (attr) { 83062306a36Sopenharmony_ci case IFLA_STATS_LINK_XSTATS: 83162306a36Sopenharmony_ci case IFLA_STATS_LINK_XSTATS_SLAVE: 83262306a36Sopenharmony_ci break; 83362306a36Sopenharmony_ci default: 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci return bond_3ad_stats_size() + nla_total_size(0); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic int bond_fill_linkxstats(struct sk_buff *skb, 84162306a36Sopenharmony_ci const struct net_device *dev, 84262306a36Sopenharmony_ci int *prividx, int attr) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci struct nlattr *nla __maybe_unused; 84562306a36Sopenharmony_ci struct slave *slave = NULL; 84662306a36Sopenharmony_ci struct nlattr *nest, *nest2; 84762306a36Sopenharmony_ci struct bonding *bond; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci switch (attr) { 85062306a36Sopenharmony_ci case IFLA_STATS_LINK_XSTATS: 85162306a36Sopenharmony_ci bond = netdev_priv(dev); 85262306a36Sopenharmony_ci break; 85362306a36Sopenharmony_ci case IFLA_STATS_LINK_XSTATS_SLAVE: 85462306a36Sopenharmony_ci slave = bond_slave_get_rtnl(dev); 85562306a36Sopenharmony_ci if (!slave) 85662306a36Sopenharmony_ci return 0; 85762306a36Sopenharmony_ci bond = slave->bond; 85862306a36Sopenharmony_ci break; 85962306a36Sopenharmony_ci default: 86062306a36Sopenharmony_ci return -EINVAL; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci nest = nla_nest_start_noflag(skb, LINK_XSTATS_TYPE_BOND); 86462306a36Sopenharmony_ci if (!nest) 86562306a36Sopenharmony_ci return -EMSGSIZE; 86662306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) { 86762306a36Sopenharmony_ci struct bond_3ad_stats *stats; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (slave) 87062306a36Sopenharmony_ci stats = &SLAVE_AD_INFO(slave)->stats; 87162306a36Sopenharmony_ci else 87262306a36Sopenharmony_ci stats = &BOND_AD_INFO(bond).stats; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci nest2 = nla_nest_start_noflag(skb, BOND_XSTATS_3AD); 87562306a36Sopenharmony_ci if (!nest2) { 87662306a36Sopenharmony_ci nla_nest_end(skb, nest); 87762306a36Sopenharmony_ci return -EMSGSIZE; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (bond_3ad_stats_fill(skb, stats)) { 88162306a36Sopenharmony_ci nla_nest_cancel(skb, nest2); 88262306a36Sopenharmony_ci nla_nest_end(skb, nest); 88362306a36Sopenharmony_ci return -EMSGSIZE; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci nla_nest_end(skb, nest2); 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci nla_nest_end(skb, nest); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return 0; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistruct rtnl_link_ops bond_link_ops __read_mostly = { 89362306a36Sopenharmony_ci .kind = "bond", 89462306a36Sopenharmony_ci .priv_size = sizeof(struct bonding), 89562306a36Sopenharmony_ci .setup = bond_setup, 89662306a36Sopenharmony_ci .maxtype = IFLA_BOND_MAX, 89762306a36Sopenharmony_ci .policy = bond_policy, 89862306a36Sopenharmony_ci .validate = bond_validate, 89962306a36Sopenharmony_ci .newlink = bond_newlink, 90062306a36Sopenharmony_ci .changelink = bond_changelink, 90162306a36Sopenharmony_ci .get_size = bond_get_size, 90262306a36Sopenharmony_ci .fill_info = bond_fill_info, 90362306a36Sopenharmony_ci .get_num_tx_queues = bond_get_num_tx_queues, 90462306a36Sopenharmony_ci .get_num_rx_queues = bond_get_num_tx_queues, /* Use the same number 90562306a36Sopenharmony_ci as for TX queues */ 90662306a36Sopenharmony_ci .fill_linkxstats = bond_fill_linkxstats, 90762306a36Sopenharmony_ci .get_linkxstats_size = bond_get_linkxstats_size, 90862306a36Sopenharmony_ci .slave_maxtype = IFLA_BOND_SLAVE_MAX, 90962306a36Sopenharmony_ci .slave_policy = bond_slave_policy, 91062306a36Sopenharmony_ci .slave_changelink = bond_slave_changelink, 91162306a36Sopenharmony_ci .get_slave_size = bond_get_slave_size, 91262306a36Sopenharmony_ci .fill_slave_info = bond_fill_slave_info, 91362306a36Sopenharmony_ci}; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ciint __init bond_netlink_init(void) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci return rtnl_link_register(&bond_link_ops); 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_civoid bond_netlink_fini(void) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci rtnl_link_unregister(&bond_link_ops); 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ciMODULE_ALIAS_RTNL_LINK("bond"); 926