diff options
Diffstat (limited to 'kernel/drivers/net/bonding')
-rw-r--r-- | kernel/drivers/net/bonding/bond_3ad.c | 141 | ||||
-rw-r--r-- | kernel/drivers/net/bonding/bond_main.c | 192 | ||||
-rw-r--r-- | kernel/drivers/net/bonding/bond_netlink.c | 79 | ||||
-rw-r--r-- | kernel/drivers/net/bonding/bond_options.c | 111 | ||||
-rw-r--r-- | kernel/drivers/net/bonding/bond_procfs.c | 93 | ||||
-rw-r--r-- | kernel/drivers/net/bonding/bond_sysfs.c | 72 | ||||
-rw-r--r-- | kernel/drivers/net/bonding/bond_sysfs_slave.c | 32 |
7 files changed, 506 insertions, 214 deletions
diff --git a/kernel/drivers/net/bonding/bond_3ad.c b/kernel/drivers/net/bonding/bond_3ad.c index fbd54f0e3..940e2ebbd 100644 --- a/kernel/drivers/net/bonding/bond_3ad.c +++ b/kernel/drivers/net/bonding/bond_3ad.c @@ -75,10 +75,10 @@ /* Port Key definitions * key is determined according to the link speed, duplex and * user key (which is yet not supported) - * -------------------------------------------------------------- - * Port key : | User key | Speed | Duplex | - * -------------------------------------------------------------- - * 16 6 1 0 + * -------------------------------------------------------------- + * Port key | User key (10 bits) | Speed (5 bits) | Duplex| + * -------------------------------------------------------------- + * |15 6|5 1|0 */ #define AD_DUPLEX_KEY_MASKS 0x1 #define AD_SPEED_KEY_MASKS 0x3E @@ -127,6 +127,7 @@ static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port); static void ad_marker_response_received(struct bond_marker *marker, struct port *port); +static void ad_update_actor_keys(struct port *port, bool reset); /* ================= api to bonding and kernel code ================== */ @@ -327,14 +328,12 @@ static u16 __get_link_speed(struct port *port) static u8 __get_duplex(struct port *port) { struct slave *slave = port->slave; - u8 retval; + u8 retval = 0x0; /* handling a special case: when the configuration starts with * link down, it sets the duplex to 0. */ - if (slave->link != BOND_LINK_UP) { - retval = 0x0; - } else { + if (slave->link == BOND_LINK_UP) { switch (slave->duplex) { case DUPLEX_FULL: retval = 0x1; @@ -1870,8 +1869,6 @@ static void ad_marker_info_received(struct bond_marker *marker_info, static void ad_marker_response_received(struct bond_marker *marker, struct port *port) { - marker = NULL; - port = NULL; /* DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW */ } @@ -1908,8 +1905,14 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution) BOND_AD_INFO(bond).aggregator_identifier = 0; - BOND_AD_INFO(bond).system.sys_priority = 0xFFFF; - BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr); + BOND_AD_INFO(bond).system.sys_priority = + bond->params.ad_actor_sys_prio; + if (is_zero_ether_addr(bond->params.ad_actor_system)) + BOND_AD_INFO(bond).system.sys_mac_addr = + *((struct mac_addr *)bond->dev->dev_addr); + else + BOND_AD_INFO(bond).system.sys_mac_addr = + *((struct mac_addr *)bond->params.ad_actor_system); /* initialize how many times this module is called in one * second (should be about every 100ms) @@ -1945,20 +1948,15 @@ void bond_3ad_bind_slave(struct slave *slave) port->slave = slave; port->actor_port_number = SLAVE_AD_INFO(slave)->id; - /* key is determined according to the link speed, duplex and user key(which - * is yet not supported) - */ - port->actor_admin_port_key = 0; - port->actor_admin_port_key |= __get_duplex(port); - port->actor_admin_port_key |= (__get_link_speed(port) << 1); - port->actor_oper_port_key = port->actor_admin_port_key; - /* if the port is not full duplex, then the port should be not - * lacp Enabled + /* key is determined according to the link speed, duplex and + * user key */ - if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS)) - port->sm_vars &= ~AD_PORT_LACP_ENABLED; + port->actor_admin_port_key = bond->params.ad_user_port_key << 6; + ad_update_actor_keys(port, false); /* actor system is the bond's system */ port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr; + port->actor_system_priority = + BOND_AD_INFO(bond).system.sys_priority; /* tx timer(to verify that no more than MAX_TX_IN_SECOND * lacpdu's are sent in one second) */ @@ -2304,45 +2302,60 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, } /** - * bond_3ad_adapter_speed_changed - handle a slave's speed change indication - * @slave: slave struct to work on + * ad_update_actor_keys - Update the oper / admin keys for a port based on + * its current speed and duplex settings. * - * Handle reselection of aggregator (if needed) for this port. + * @port: the port we'are looking at + * @reset: Boolean to just reset the speed and the duplex part of the key + * + * The logic to change the oper / admin keys is: + * (a) A full duplex port can participate in LACP with partner. + * (b) When the speed is changed, LACP need to be reinitiated. */ -void bond_3ad_adapter_speed_changed(struct slave *slave) +static void ad_update_actor_keys(struct port *port, bool reset) { - struct port *port; - - port = &(SLAVE_AD_INFO(slave)->port); - - /* if slave is null, the whole port is not initialized */ - if (!port->slave) { - netdev_warn(slave->bond->dev, "speed changed for uninitialized port on %s\n", - slave->dev->name); - return; + u8 duplex = 0; + u16 ospeed = 0, speed = 0; + u16 old_oper_key = port->actor_oper_port_key; + + port->actor_admin_port_key &= ~(AD_SPEED_KEY_MASKS|AD_DUPLEX_KEY_MASKS); + if (!reset) { + speed = __get_link_speed(port); + ospeed = (old_oper_key & AD_SPEED_KEY_MASKS) >> 1; + duplex = __get_duplex(port); + port->actor_admin_port_key |= (speed << 1) | duplex; } - - spin_lock_bh(&slave->bond->mode_lock); - - port->actor_admin_port_key &= ~AD_SPEED_KEY_MASKS; - port->actor_admin_port_key |= __get_link_speed(port) << 1; port->actor_oper_port_key = port->actor_admin_port_key; - netdev_dbg(slave->bond->dev, "Port %d changed speed\n", port->actor_port_number); - /* there is no need to reselect a new aggregator, just signal the - * state machines to reinitialize - */ - port->sm_vars |= AD_PORT_BEGIN; - spin_unlock_bh(&slave->bond->mode_lock); + if (old_oper_key != port->actor_oper_port_key) { + /* Only 'duplex' port participates in LACP */ + if (duplex) + port->sm_vars |= AD_PORT_LACP_ENABLED; + else + port->sm_vars &= ~AD_PORT_LACP_ENABLED; + + if (!reset) { + if (!speed) { + netdev_err(port->slave->dev, + "speed changed to 0 for port %s", + port->slave->dev->name); + } else if (duplex && ospeed != speed) { + /* Speed change restarts LACP state-machine */ + port->sm_vars |= AD_PORT_BEGIN; + } + } + } } /** - * bond_3ad_adapter_duplex_changed - handle a slave's duplex change indication + * bond_3ad_adapter_speed_duplex_changed - handle a slave's speed / duplex + * change indication + * * @slave: slave struct to work on * * Handle reselection of aggregator (if needed) for this port. */ -void bond_3ad_adapter_duplex_changed(struct slave *slave) +void bond_3ad_adapter_speed_duplex_changed(struct slave *slave) { struct port *port; @@ -2350,25 +2363,16 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) /* if slave is null, the whole port is not initialized */ if (!port->slave) { - netdev_warn(slave->bond->dev, "duplex changed for uninitialized port on %s\n", + netdev_warn(slave->bond->dev, + "speed/duplex changed for uninitialized port %s\n", slave->dev->name); return; } spin_lock_bh(&slave->bond->mode_lock); - - port->actor_admin_port_key &= ~AD_DUPLEX_KEY_MASKS; - port->actor_admin_port_key |= __get_duplex(port); - port->actor_oper_port_key = port->actor_admin_port_key; - netdev_dbg(slave->bond->dev, "Port %d slave %s changed duplex\n", + ad_update_actor_keys(port, false); + netdev_dbg(slave->bond->dev, "Port %d slave %s changed speed/duplex\n", port->actor_port_number, slave->dev->name); - if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS) - port->sm_vars |= AD_PORT_LACP_ENABLED; - /* there is no need to reselect a new aggregator, just signal the - * state machines to reinitialize - */ - port->sm_vars |= AD_PORT_BEGIN; - spin_unlock_bh(&slave->bond->mode_lock); } @@ -2400,26 +2404,17 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) * on link up we are forcing recheck on the duplex and speed since * some of he adaptors(ce1000.lan) report. */ - port->actor_admin_port_key &= ~(AD_DUPLEX_KEY_MASKS|AD_SPEED_KEY_MASKS); if (link == BOND_LINK_UP) { port->is_enabled = true; - port->actor_admin_port_key |= - (__get_link_speed(port) << 1) | __get_duplex(port); - if (port->actor_admin_port_key & AD_DUPLEX_KEY_MASKS) - port->sm_vars |= AD_PORT_LACP_ENABLED; + ad_update_actor_keys(port, false); } else { /* link has failed */ port->is_enabled = false; - port->sm_vars &= ~AD_PORT_LACP_ENABLED; + ad_update_actor_keys(port, true); } - port->actor_oper_port_key = port->actor_admin_port_key; netdev_dbg(slave->bond->dev, "Port %d changed link status to %s\n", port->actor_port_number, link == BOND_LINK_UP ? "UP" : "DOWN"); - /* there is no need to reselect a new aggregator, just signal the - * state machines to reinitialize - */ - port->sm_vars |= AD_PORT_BEGIN; spin_unlock_bh(&slave->bond->mode_lock); diff --git a/kernel/drivers/net/bonding/bond_main.c b/kernel/drivers/net/bonding/bond_main.c index 16d87bf8a..28bbca0af 100644 --- a/kernel/drivers/net/bonding/bond_main.c +++ b/kernel/drivers/net/bonding/bond_main.c @@ -76,7 +76,7 @@ #include <net/netns/generic.h> #include <net/pkt_sched.h> #include <linux/rculist.h> -#include <net/flow_keys.h> +#include <net/flow_dissector.h> #include <net/switchdev.h> #include <net/bonding.h> #include <net/bond_3ad.h> @@ -214,6 +214,8 @@ static void bond_uninit(struct net_device *bond_dev); static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev, struct rtnl_link_stats64 *stats); static void bond_slave_arr_handler(struct work_struct *work); +static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act, + int mod); /*---------------------------- General routines -----------------------------*/ @@ -709,40 +711,57 @@ out: } -static bool bond_should_change_active(struct bonding *bond) +static struct slave *bond_choose_primary_or_current(struct bonding *bond) { struct slave *prim = rtnl_dereference(bond->primary_slave); struct slave *curr = rtnl_dereference(bond->curr_active_slave); - if (!prim || !curr || curr->link != BOND_LINK_UP) - return true; + if (!prim || prim->link != BOND_LINK_UP) { + if (!curr || curr->link != BOND_LINK_UP) + return NULL; + return curr; + } + if (bond->force_primary) { bond->force_primary = false; - return true; + return prim; + } + + if (!curr || curr->link != BOND_LINK_UP) + return prim; + + /* At this point, prim and curr are both up */ + switch (bond->params.primary_reselect) { + case BOND_PRI_RESELECT_ALWAYS: + return prim; + case BOND_PRI_RESELECT_BETTER: + if (prim->speed < curr->speed) + return curr; + if (prim->speed == curr->speed && prim->duplex <= curr->duplex) + return curr; + return prim; + case BOND_PRI_RESELECT_FAILURE: + return curr; + default: + netdev_err(bond->dev, "impossible primary_reselect %d\n", + bond->params.primary_reselect); + return curr; } - if (bond->params.primary_reselect == BOND_PRI_RESELECT_BETTER && - (prim->speed < curr->speed || - (prim->speed == curr->speed && prim->duplex <= curr->duplex))) - return false; - if (bond->params.primary_reselect == BOND_PRI_RESELECT_FAILURE) - return false; - return true; } /** - * find_best_interface - select the best available slave to be the active one + * bond_find_best_slave - select the best available slave to be the active one * @bond: our bonding struct */ static struct slave *bond_find_best_slave(struct bonding *bond) { - struct slave *slave, *bestslave = NULL, *primary; + struct slave *slave, *bestslave = NULL; struct list_head *iter; int mintime = bond->params.updelay; - primary = rtnl_dereference(bond->primary_slave); - if (primary && primary->link == BOND_LINK_UP && - bond_should_change_active(bond)) - return primary; + slave = bond_choose_primary_or_current(bond); + if (slave) + return slave; bond_for_each_slave(bond, slave, iter) { if (slave->link == BOND_LINK_UP) @@ -769,6 +788,7 @@ static bool bond_should_notify_peers(struct bonding *bond) slave ? slave->dev->name : "NULL"); if (!slave || !bond->send_peer_notif || + !netif_carrier_ok(bond->dev) || test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) return false; @@ -961,7 +981,6 @@ static void bond_poll_controller(struct net_device *bond_dev) if (bond_3ad_get_active_agg_info(bond, &ad_info)) return; - rcu_read_lock_bh(); bond_for_each_slave_rcu(bond, slave, iter) { ops = slave->dev->netdev_ops; if (!bond_slave_is_up(slave) || !ops->ndo_poll_controller) @@ -982,7 +1001,6 @@ static void bond_poll_controller(struct net_device *bond_dev) ops->ndo_poll_controller(slave->dev); up(&ni->dev_lock); } - rcu_read_unlock_bh(); } static void bond_netpoll_cleanup(struct net_device *bond_dev) @@ -1035,10 +1053,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, netdev_features_t mask; struct slave *slave; - /* If any slave has the offload feature flag set, - * set the offload flag on the bond. - */ - mask = features | NETIF_F_HW_SWITCH_OFFLOAD; + mask = features; features &= ~NETIF_F_ONE_FOR_ALL; features |= NETIF_F_ALL_FOR_ALL; @@ -1058,7 +1073,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, NETIF_F_HIGHDMA | NETIF_F_LRO) #define BOND_ENC_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_RXCSUM |\ - NETIF_F_TSO) + NETIF_F_ALL_TSO) static void bond_compute_features(struct bonding *bond) { @@ -1194,7 +1209,6 @@ static int bond_master_upper_dev_link(struct net_device *bond_dev, err = netdev_master_upper_dev_link_private(slave_dev, bond_dev, slave); if (err) return err; - slave_dev->flags |= IFF_SLAVE; rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE, GFP_KERNEL); return 0; } @@ -1452,6 +1466,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } } + /* set slave flag before open to prevent IPv6 addrconf */ + slave_dev->flags |= IFF_SLAVE; + /* open the slave since the application closed it */ res = dev_open(slave_dev); if (res) { @@ -1712,6 +1729,7 @@ err_close: dev_close(slave_dev); err_restore_mac: + slave_dev->flags &= ~IFF_SLAVE; if (!bond->params.fail_over_mac || BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { /* XXX TODO - fom follow mode needs to change master's @@ -1731,9 +1749,17 @@ err_free: err_undo_flags: /* Enslave of first slave has failed and we need to fix master's mac */ - if (!bond_has_slaves(bond) && - ether_addr_equal_64bits(bond_dev->dev_addr, slave_dev->dev_addr)) - eth_hw_addr_random(bond_dev); + if (!bond_has_slaves(bond)) { + if (ether_addr_equal_64bits(bond_dev->dev_addr, + slave_dev->dev_addr)) + eth_hw_addr_random(bond_dev); + if (bond_dev->type != ARPHRD_ETHER) { + dev_close(bond_dev); + ether_setup(bond_dev); + bond_dev->flags |= IFF_MASTER; + bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING; + } + } return res; } @@ -2394,7 +2420,7 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave) { struct arphdr *arp = (struct arphdr *)skb->data; - struct slave *curr_active_slave; + struct slave *curr_active_slave, *curr_arp_slave; unsigned char *arp_ptr; __be32 sip, tip; int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP); @@ -2441,26 +2467,41 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, &sip, &tip); curr_active_slave = rcu_dereference(bond->curr_active_slave); + curr_arp_slave = rcu_dereference(bond->current_arp_slave); - /* Backup slaves won't see the ARP reply, but do come through - * here for each ARP probe (so we swap the sip/tip to validate - * the probe). In a "redundant switch, common router" type of - * configuration, the ARP probe will (hopefully) travel from - * the active, through one switch, the router, then the other - * switch before reaching the backup. + /* We 'trust' the received ARP enough to validate it if: + * + * (a) the slave receiving the ARP is active (which includes the + * current ARP slave, if any), or + * + * (b) the receiving slave isn't active, but there is a currently + * active slave and it received valid arp reply(s) after it became + * the currently active slave, or + * + * (c) there is an ARP slave that sent an ARP during the prior ARP + * interval, and we receive an ARP reply on any slave. We accept + * these because switch FDB update delays may deliver the ARP + * reply to a slave other than the sender of the ARP request. * - * We 'trust' the arp requests if there is an active slave and - * it received valid arp reply(s) after it became active. This - * is done to avoid endless looping when we can't reach the + * Note: for (b), backup slaves are receiving the broadcast ARP + * request, not a reply. This request passes from the sending + * slave through the L2 switch(es) to the receiving slave. Since + * this is checking the request, sip/tip are swapped for + * validation. + * + * This is done to avoid endless looping when we can't reach the * arp_ip_target and fool ourselves with our own arp requests. */ - if (bond_is_active_slave(slave)) bond_validate_arp(bond, slave, sip, tip); else if (curr_active_slave && time_after(slave_last_rx(bond, curr_active_slave), curr_active_slave->last_link_up)) bond_validate_arp(bond, slave, tip, sip); + else if (curr_arp_slave && (arp->ar_op == htons(ARPOP_REPLY)) && + bond_time_in_interval(bond, + dev_trans_start(curr_arp_slave->dev), 1)) + bond_validate_arp(bond, slave, sip, tip); out_unlock: if (arp != (struct arphdr *)skb->data) @@ -2923,8 +2964,6 @@ static int bond_slave_netdev_event(unsigned long event, struct slave *slave = bond_slave_get_rtnl(slave_dev), *primary; struct bonding *bond; struct net_device *bond_dev; - u32 old_speed; - u8 old_duplex; /* A netdev event can be generated while enslaving a device * before netdev_rx_handler_register is called in which case @@ -2945,17 +2984,9 @@ static int bond_slave_netdev_event(unsigned long event, break; case NETDEV_UP: case NETDEV_CHANGE: - old_speed = slave->speed; - old_duplex = slave->duplex; - bond_update_speed_duplex(slave); - - if (BOND_MODE(bond) == BOND_MODE_8023AD) { - if (old_speed != slave->speed) - bond_3ad_adapter_speed_changed(slave); - if (old_duplex != slave->duplex) - bond_3ad_adapter_duplex_changed(slave); - } + if (BOND_MODE(bond) == BOND_MODE_8023AD) + bond_3ad_adapter_speed_duplex_changed(slave); /* Fallthrough */ case NETDEV_DOWN: /* Refresh slave-array if applicable! @@ -3075,16 +3106,15 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, int noff, proto = -1; if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23) - return skb_flow_dissect(skb, fk); + return skb_flow_dissect_flow_keys(skb, fk, 0); - fk->ports = 0; + fk->ports.ports = 0; noff = skb_network_offset(skb); if (skb->protocol == htons(ETH_P_IP)) { if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph)))) return false; iph = ip_hdr(skb); - fk->src = iph->saddr; - fk->dst = iph->daddr; + iph_to_flow_copy_v4addrs(fk, iph); noff += iph->ihl << 2; if (!ip_is_fragment(iph)) proto = iph->protocol; @@ -3092,15 +3122,14 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph6)))) return false; iph6 = ipv6_hdr(skb); - fk->src = (__force __be32)ipv6_addr_hash(&iph6->saddr); - fk->dst = (__force __be32)ipv6_addr_hash(&iph6->daddr); + iph_to_flow_copy_v6addrs(fk, iph6); noff += sizeof(*iph6); proto = iph6->nexthdr; } else { return false; } if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34 && proto >= 0) - fk->ports = skb_flow_get_ports(skb, noff, proto); + fk->ports.ports = skb_flow_get_ports(skb, noff, proto); return true; } @@ -3118,6 +3147,10 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb) struct flow_keys flow; u32 hash; + if (bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP34 && + skb->l4_hash) + return skb->hash; + if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 || !bond_flow_dissect(bond, skb, &flow)) return bond_eth_hash(skb); @@ -3126,8 +3159,9 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb) bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23) hash = bond_eth_hash(skb); else - hash = (__force u32)flow.ports; - hash ^= (__force u32)flow.dst ^ (__force u32)flow.src; + hash = (__force u32)flow.ports.ports; + hash ^= (__force u32)flow_get_u32_dst(&flow) ^ + (__force u32)flow_get_u32_src(&flow); hash ^= (hash >> 16); hash ^= (hash >> 8); @@ -3759,7 +3793,6 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) struct slave *slave; struct list_head *iter; struct bond_up_slave *new_arr, *old_arr; - int slaves_in_agg; int agg_id = 0; int ret = 0; @@ -3790,7 +3823,6 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) } goto out; } - slaves_in_agg = ad_info.ports; agg_id = ad_info.aggregator_id; } bond_for_each_slave(bond, slave, iter) { @@ -4060,8 +4092,12 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_add_slave = bond_enslave, .ndo_del_slave = bond_release, .ndo_fix_features = bond_fix_features, - .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink, - .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink, + .ndo_bridge_setlink = switchdev_port_bridge_setlink, + .ndo_bridge_getlink = switchdev_port_bridge_getlink, + .ndo_bridge_dellink = switchdev_port_bridge_dellink, + .ndo_fdb_add = switchdev_port_fdb_add, + .ndo_fdb_del = switchdev_port_fdb_del, + .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_features_check = passthru_features_check, }; @@ -4097,9 +4133,8 @@ void bond_setup(struct net_device *bond_dev) SET_NETDEV_DEVTYPE(bond_dev, &bond_type); /* Initialize the device options */ - bond_dev->tx_queue_len = 0; bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; - bond_dev->priv_flags |= IFF_BONDING | IFF_UNICAST_FLT; + bond_dev->priv_flags |= IFF_BONDING | IFF_UNICAST_FLT | IFF_NO_QUEUE; bond_dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING); /* don't acquire bond device's netif_tx_lock when transmitting */ @@ -4161,6 +4196,8 @@ static int bond_check_params(struct bond_params *params) struct bond_opt_value newval; const struct bond_opt_value *valptr; int arp_all_targets_value; + u16 ad_actor_sys_prio = 0; + u16 ad_user_port_key = 0; /* Convert string parameters. */ if (mode) { @@ -4455,6 +4492,24 @@ static int bond_check_params(struct bond_params *params) fail_over_mac_value = BOND_FOM_NONE; } + bond_opt_initstr(&newval, "default"); + valptr = bond_opt_parse( + bond_opt_get(BOND_OPT_AD_ACTOR_SYS_PRIO), + &newval); + if (!valptr) { + pr_err("Error: No ad_actor_sys_prio default value"); + return -EINVAL; + } + ad_actor_sys_prio = valptr->value; + + valptr = bond_opt_parse(bond_opt_get(BOND_OPT_AD_USER_PORT_KEY), + &newval); + if (!valptr) { + pr_err("Error: No ad_user_port_key default value"); + return -EINVAL; + } + ad_user_port_key = valptr->value; + if (lp_interval == 0) { pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n", INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL); @@ -4483,6 +4538,9 @@ static int bond_check_params(struct bond_params *params) params->lp_interval = lp_interval; params->packets_per_slave = packets_per_slave; params->tlb_dynamic_lb = 1; /* Default value */ + params->ad_actor_sys_prio = ad_actor_sys_prio; + eth_zero_addr(params->ad_actor_system); + params->ad_user_port_key = ad_user_port_key; if (packets_per_slave > 0) { params->reciprocal_packets_per_slave = reciprocal_value(packets_per_slave); diff --git a/kernel/drivers/net/bonding/bond_netlink.c b/kernel/drivers/net/bonding/bond_netlink.c index 7b1124366..db760e841 100644 --- a/kernel/drivers/net/bonding/bond_netlink.c +++ b/kernel/drivers/net/bonding/bond_netlink.c @@ -28,6 +28,8 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev, nla_total_size(MAX_ADDR_LEN) + /* IFLA_BOND_SLAVE_PERM_HWADDR */ nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_QUEUE_ID */ nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_AGGREGATOR_ID */ + nla_total_size(sizeof(u8)) + /* IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */ 0; } @@ -56,12 +58,23 @@ static int bond_fill_slave_info(struct sk_buff *skb, if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { const struct aggregator *agg; + const struct port *ad_port; + ad_port = &SLAVE_AD_INFO(slave)->port; agg = SLAVE_AD_INFO(slave)->port.aggregator; - if (agg) + if (agg) { if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, agg->aggregator_identifier)) goto nla_put_failure; + if (nla_put_u8(skb, + IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, + ad_port->actor_oper_port_state)) + goto nla_put_failure; + if (nla_put_u16(skb, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + ad_port->partner_oper.port_state)) + goto nla_put_failure; + } } return 0; @@ -94,6 +107,11 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_AD_LACP_RATE] = { .type = NLA_U8 }, [IFLA_BOND_AD_SELECT] = { .type = NLA_U8 }, [IFLA_BOND_AD_INFO] = { .type = NLA_NESTED }, + [IFLA_BOND_AD_ACTOR_SYS_PRIO] = { .type = NLA_U16 }, + [IFLA_BOND_AD_USER_PORT_KEY] = { .type = NLA_U16 }, + [IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NLA_BINARY, + .len = ETH_ALEN }, + [IFLA_BOND_TLB_DYNAMIC_LB] = { .type = NLA_U8 }, }; static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { @@ -379,6 +397,43 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_AD_ACTOR_SYS_PRIO]) { + int actor_sys_prio = + nla_get_u16(data[IFLA_BOND_AD_ACTOR_SYS_PRIO]); + + bond_opt_initval(&newval, actor_sys_prio); + err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval); + if (err) + return err; + } + if (data[IFLA_BOND_AD_USER_PORT_KEY]) { + int port_key = + nla_get_u16(data[IFLA_BOND_AD_USER_PORT_KEY]); + + bond_opt_initval(&newval, port_key); + err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval); + if (err) + return err; + } + if (data[IFLA_BOND_AD_ACTOR_SYSTEM]) { + if (nla_len(data[IFLA_BOND_AD_ACTOR_SYSTEM]) != ETH_ALEN) + return -EINVAL; + + bond_opt_initval(&newval, + nla_get_be64(data[IFLA_BOND_AD_ACTOR_SYSTEM])); + err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval); + if (err) + return err; + } + if (data[IFLA_BOND_TLB_DYNAMIC_LB]) { + int dynamic_lb = nla_get_u8(data[IFLA_BOND_TLB_DYNAMIC_LB]); + + bond_opt_initval(&newval, dynamic_lb); + err = __bond_opt_set(bond, BOND_OPT_TLB_DYNAMIC_LB, &newval); + if (err) + return err; + } + return 0; } @@ -426,6 +481,10 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_ACTOR_KEY */ nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_INFO_PARTNER_KEY*/ nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_INFO_PARTNER_MAC*/ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_ACTOR_SYS_PRIO */ + nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_USER_PORT_KEY */ + nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_ACTOR_SYSTEM */ + nla_total_size(sizeof(u8)) + /* IFLA_BOND_TLB_DYNAMIC_LB */ 0; } @@ -548,9 +607,27 @@ static int bond_fill_info(struct sk_buff *skb, bond->params.ad_select)) goto nla_put_failure; + if (nla_put_u8(skb, IFLA_BOND_TLB_DYNAMIC_LB, + bond->params.tlb_dynamic_lb)) + goto nla_put_failure; + if (BOND_MODE(bond) == BOND_MODE_8023AD) { struct ad_info info; + if (capable(CAP_NET_ADMIN)) { + if (nla_put_u16(skb, IFLA_BOND_AD_ACTOR_SYS_PRIO, + bond->params.ad_actor_sys_prio)) + goto nla_put_failure; + + if (nla_put_u16(skb, IFLA_BOND_AD_USER_PORT_KEY, + bond->params.ad_user_port_key)) + goto nla_put_failure; + + if (nla_put(skb, IFLA_BOND_AD_ACTOR_SYSTEM, + sizeof(bond->params.ad_actor_system), + &bond->params.ad_actor_system)) + goto nla_put_failure; + } if (!bond_3ad_get_active_agg_info(bond, &info)) { struct nlattr *nest; diff --git a/kernel/drivers/net/bonding/bond_options.c b/kernel/drivers/net/bonding/bond_options.c index e8d3c1d35..55e93b6b6 100644 --- a/kernel/drivers/net/bonding/bond_options.c +++ b/kernel/drivers/net/bonding/bond_options.c @@ -70,6 +70,12 @@ static int bond_option_slaves_set(struct bonding *bond, const struct bond_opt_value *newval); static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, const struct bond_opt_value *newval); +static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_ad_actor_system_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_ad_user_port_key_set(struct bonding *bond, + const struct bond_opt_value *newval); static const struct bond_opt_value bond_mode_tbl[] = { @@ -186,6 +192,18 @@ static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = { { NULL, -1, 0} }; +static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = { + { "minval", 1, BOND_VALFLAG_MIN}, + { "maxval", 65535, BOND_VALFLAG_MAX | BOND_VALFLAG_DEFAULT}, + { NULL, -1, 0}, +}; + +static const struct bond_opt_value bond_ad_user_port_key_tbl[] = { + { "minval", 0, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT}, + { "maxval", 1023, BOND_VALFLAG_MAX}, + { NULL, -1, 0}, +}; + static const struct bond_option bond_opts[BOND_OPT_LAST] = { [BOND_OPT_MODE] = { .id = BOND_OPT_MODE, @@ -379,6 +397,36 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .values = bond_tlb_dynamic_lb_tbl, .flags = BOND_OPTFLAG_IFDOWN, .set = bond_option_tlb_dynamic_lb_set, + }, + [BOND_OPT_AD_ACTOR_SYS_PRIO] = { + .id = BOND_OPT_AD_ACTOR_SYS_PRIO, + .name = "ad_actor_sys_prio", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), + .flags = BOND_OPTFLAG_IFDOWN, + .values = bond_ad_actor_sys_prio_tbl, + .set = bond_option_ad_actor_sys_prio_set, + }, + [BOND_OPT_AD_ACTOR_SYSTEM] = { + .id = BOND_OPT_AD_ACTOR_SYSTEM, + .name = "ad_actor_system", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), + .flags = BOND_OPTFLAG_RAWVAL | BOND_OPTFLAG_IFDOWN, + .set = bond_option_ad_actor_system_set, + }, + [BOND_OPT_AD_USER_PORT_KEY] = { + .id = BOND_OPT_AD_USER_PORT_KEY, + .name = "ad_user_port_key", + .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)), + .flags = BOND_OPTFLAG_IFDOWN, + .values = bond_ad_user_port_key_tbl, + .set = bond_option_ad_user_port_key_set, + }, + [BOND_OPT_NUM_PEER_NOTIF_ALIAS] = { + .id = BOND_OPT_NUM_PEER_NOTIF_ALIAS, + .name = "num_grat_arp", + .desc = "Number of peer notifications to send on failover event", + .values = bond_num_peer_notif_tbl, + .set = bond_option_num_peer_notif_set } }; @@ -689,19 +737,6 @@ static int bond_option_mode_set(struct bonding *bond, return 0; } -static struct net_device *__bond_option_active_slave_get(struct bonding *bond, - struct slave *slave) -{ - return bond_uses_primary(bond) && slave ? slave->dev : NULL; -} - -struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond) -{ - struct slave *slave = rcu_dereference(bond->curr_active_slave); - - return __bond_option_active_slave_get(bond, slave); -} - static int bond_option_active_slave_set(struct bonding *bond, const struct bond_opt_value *newval) { @@ -1349,3 +1384,53 @@ static int bond_option_tlb_dynamic_lb_set(struct bonding *bond, return 0; } + +static int bond_option_ad_actor_sys_prio_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + netdev_info(bond->dev, "Setting ad_actor_sys_prio to %llu\n", + newval->value); + + bond->params.ad_actor_sys_prio = newval->value; + return 0; +} + +static int bond_option_ad_actor_system_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + u8 macaddr[ETH_ALEN]; + u8 *mac; + int i; + + if (newval->string) { + i = sscanf(newval->string, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &macaddr[0], &macaddr[1], &macaddr[2], + &macaddr[3], &macaddr[4], &macaddr[5]); + if (i != ETH_ALEN) + goto err; + mac = macaddr; + } else { + mac = (u8 *)&newval->value; + } + + if (!is_valid_ether_addr(mac)) + goto err; + + netdev_info(bond->dev, "Setting ad_actor_system to %pM\n", mac); + ether_addr_copy(bond->params.ad_actor_system, mac); + return 0; + +err: + netdev_err(bond->dev, "Invalid MAC address.\n"); + return -EINVAL; +} + +static int bond_option_ad_user_port_key_set(struct bonding *bond, + const struct bond_opt_value *newval) +{ + netdev_info(bond->dev, "Setting ad_user_port_key to %llu\n", + newval->value); + + bond->params.ad_user_port_key = newval->value; + return 0; +} diff --git a/kernel/drivers/net/bonding/bond_procfs.c b/kernel/drivers/net/bonding/bond_procfs.c index b20b35acb..f514fe5e8 100644 --- a/kernel/drivers/net/bonding/bond_procfs.c +++ b/kernel/drivers/net/bonding/bond_procfs.c @@ -135,23 +135,30 @@ static void bond_info_show_master(struct seq_file *seq) bond->params.ad_select); seq_printf(seq, "Aggregator selection policy (ad_select): %s\n", optval->string); - - if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { - seq_printf(seq, "bond %s has no active aggregator\n", - bond->dev->name); - } else { - seq_printf(seq, "Active Aggregator Info:\n"); - - seq_printf(seq, "\tAggregator ID: %d\n", - ad_info.aggregator_id); - seq_printf(seq, "\tNumber of ports: %d\n", - ad_info.ports); - seq_printf(seq, "\tActor Key: %d\n", - ad_info.actor_key); - seq_printf(seq, "\tPartner Key: %d\n", - ad_info.partner_key); - seq_printf(seq, "\tPartner Mac Address: %pM\n", - ad_info.partner_system); + if (capable(CAP_NET_ADMIN)) { + seq_printf(seq, "System priority: %d\n", + BOND_AD_INFO(bond).system.sys_priority); + seq_printf(seq, "System MAC address: %pM\n", + &BOND_AD_INFO(bond).system.sys_mac_addr); + + if (__bond_3ad_get_active_agg_info(bond, &ad_info)) { + seq_printf(seq, + "bond %s has no active aggregator\n", + bond->dev->name); + } else { + seq_printf(seq, "Active Aggregator Info:\n"); + + seq_printf(seq, "\tAggregator ID: %d\n", + ad_info.aggregator_id); + seq_printf(seq, "\tNumber of ports: %d\n", + ad_info.ports); + seq_printf(seq, "\tActor Key: %d\n", + ad_info.actor_key); + seq_printf(seq, "\tPartner Key: %d\n", + ad_info.partner_key); + seq_printf(seq, "\tPartner Mac Address: %pM\n", + ad_info.partner_system); + } } } } @@ -195,29 +202,35 @@ static void bond_info_show_slave(struct seq_file *seq, seq_printf(seq, "Partner Churned Count: %d\n", port->churn_partner_count); - seq_puts(seq, "details actor lacp pdu:\n"); - seq_printf(seq, " system priority: %d\n", - port->actor_system_priority); - seq_printf(seq, " port key: %d\n", - port->actor_oper_port_key); - seq_printf(seq, " port priority: %d\n", - port->actor_port_priority); - seq_printf(seq, " port number: %d\n", - port->actor_port_number); - seq_printf(seq, " port state: %d\n", - port->actor_oper_port_state); - - seq_puts(seq, "details partner lacp pdu:\n"); - seq_printf(seq, " system priority: %d\n", - port->partner_oper.system_priority); - seq_printf(seq, " oper key: %d\n", - port->partner_oper.key); - seq_printf(seq, " port priority: %d\n", - port->partner_oper.port_priority); - seq_printf(seq, " port number: %d\n", - port->partner_oper.port_number); - seq_printf(seq, " port state: %d\n", - port->partner_oper.port_state); + if (capable(CAP_NET_ADMIN)) { + seq_puts(seq, "details actor lacp pdu:\n"); + seq_printf(seq, " system priority: %d\n", + port->actor_system_priority); + seq_printf(seq, " system mac address: %pM\n", + &port->actor_system); + seq_printf(seq, " port key: %d\n", + port->actor_oper_port_key); + seq_printf(seq, " port priority: %d\n", + port->actor_port_priority); + seq_printf(seq, " port number: %d\n", + port->actor_port_number); + seq_printf(seq, " port state: %d\n", + port->actor_oper_port_state); + + seq_puts(seq, "details partner lacp pdu:\n"); + seq_printf(seq, " system priority: %d\n", + port->partner_oper.system_priority); + seq_printf(seq, " system mac address: %pM\n", + &port->partner_oper.system); + seq_printf(seq, " oper key: %d\n", + port->partner_oper.key); + seq_printf(seq, " port priority: %d\n", + port->partner_oper.port_priority); + seq_printf(seq, " port number: %d\n", + port->partner_oper.port_number); + seq_printf(seq, " port state: %d\n", + port->partner_oper.port_state); + } } else { seq_puts(seq, "Aggregator ID: N/A\n"); } diff --git a/kernel/drivers/net/bonding/bond_sysfs.c b/kernel/drivers/net/bonding/bond_sysfs.c index 7e9e151d4..f4ae72086 100644 --- a/kernel/drivers/net/bonding/bond_sysfs.c +++ b/kernel/drivers/net/bonding/bond_sysfs.c @@ -380,7 +380,7 @@ static ssize_t bonding_show_ad_select(struct device *d, static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_sysfs_store_option); -/* Show and set the number of peer notifications to send after a failover event. */ +/* Show the number of peer notifications to send after a failover event. */ static ssize_t bonding_show_num_peer_notif(struct device *d, struct device_attribute *attr, char *buf) @@ -388,24 +388,10 @@ static ssize_t bonding_show_num_peer_notif(struct device *d, struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.num_peer_notif); } - -static ssize_t bonding_store_num_peer_notif(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct bonding *bond = to_bond(d); - int ret; - - ret = bond_opt_tryset_rtnl(bond, BOND_OPT_NUM_PEER_NOTIF, (char *)buf); - if (!ret) - ret = count; - - return ret; -} static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, - bonding_show_num_peer_notif, bonding_store_num_peer_notif); + bonding_show_num_peer_notif, bonding_sysfs_store_option); static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, - bonding_show_num_peer_notif, bonding_store_num_peer_notif); + bonding_show_num_peer_notif, bonding_sysfs_store_option); /* Show the MII monitor interval. */ static ssize_t bonding_show_miimon(struct device *d, @@ -549,7 +535,7 @@ static ssize_t bonding_show_ad_actor_key(struct device *d, int count = 0; struct bonding *bond = to_bond(d); - if (BOND_MODE(bond) == BOND_MODE_8023AD) { + if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) { struct ad_info ad_info; count = sprintf(buf, "%d\n", bond_3ad_get_active_agg_info(bond, &ad_info) @@ -569,7 +555,7 @@ static ssize_t bonding_show_ad_partner_key(struct device *d, int count = 0; struct bonding *bond = to_bond(d); - if (BOND_MODE(bond) == BOND_MODE_8023AD) { + if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) { struct ad_info ad_info; count = sprintf(buf, "%d\n", bond_3ad_get_active_agg_info(bond, &ad_info) @@ -589,7 +575,7 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d, int count = 0; struct bonding *bond = to_bond(d); - if (BOND_MODE(bond) == BOND_MODE_8023AD) { + if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) { struct ad_info ad_info; if (!bond_3ad_get_active_agg_info(bond, &ad_info)) count = sprintf(buf, "%pM\n", ad_info.partner_system); @@ -692,6 +678,49 @@ static ssize_t bonding_show_packets_per_slave(struct device *d, static DEVICE_ATTR(packets_per_slave, S_IRUGO | S_IWUSR, bonding_show_packets_per_slave, bonding_sysfs_store_option); +static ssize_t bonding_show_ad_actor_sys_prio(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) + return sprintf(buf, "%hu\n", bond->params.ad_actor_sys_prio); + + return 0; +} +static DEVICE_ATTR(ad_actor_sys_prio, S_IRUGO | S_IWUSR, + bonding_show_ad_actor_sys_prio, bonding_sysfs_store_option); + +static ssize_t bonding_show_ad_actor_system(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) + return sprintf(buf, "%pM\n", bond->params.ad_actor_system); + + return 0; +} + +static DEVICE_ATTR(ad_actor_system, S_IRUGO | S_IWUSR, + bonding_show_ad_actor_system, bonding_sysfs_store_option); + +static ssize_t bonding_show_ad_user_port_key(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + if (BOND_MODE(bond) == BOND_MODE_8023AD && capable(CAP_NET_ADMIN)) + return sprintf(buf, "%hu\n", bond->params.ad_user_port_key); + + return 0; +} +static DEVICE_ATTR(ad_user_port_key, S_IRUGO | S_IWUSR, + bonding_show_ad_user_port_key, bonding_sysfs_store_option); + static struct attribute *per_bond_attrs[] = { &dev_attr_slaves.attr, &dev_attr_mode.attr, @@ -725,6 +754,9 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_lp_interval.attr, &dev_attr_packets_per_slave.attr, &dev_attr_tlb_dynamic_lb.attr, + &dev_attr_ad_actor_sys_prio.attr, + &dev_attr_ad_actor_system.attr, + &dev_attr_ad_user_port_key.attr, NULL, }; diff --git a/kernel/drivers/net/bonding/bond_sysfs_slave.c b/kernel/drivers/net/bonding/bond_sysfs_slave.c index 23618a831..7d16c51e6 100644 --- a/kernel/drivers/net/bonding/bond_sysfs_slave.c +++ b/kernel/drivers/net/bonding/bond_sysfs_slave.c @@ -80,6 +80,36 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf) } static SLAVE_ATTR_RO(ad_aggregator_id); +static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf) +{ + const struct port *ad_port; + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { + ad_port = &SLAVE_AD_INFO(slave)->port; + if (ad_port->aggregator) + return sprintf(buf, "%u\n", + ad_port->actor_oper_port_state); + } + + return sprintf(buf, "N/A\n"); +} +static SLAVE_ATTR_RO(ad_actor_oper_port_state); + +static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf) +{ + const struct port *ad_port; + + if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) { + ad_port = &SLAVE_AD_INFO(slave)->port; + if (ad_port->aggregator) + return sprintf(buf, "%u\n", + ad_port->partner_oper.port_state); + } + + return sprintf(buf, "N/A\n"); +} +static SLAVE_ATTR_RO(ad_partner_oper_port_state); + static const struct slave_attribute *slave_attrs[] = { &slave_attr_state, &slave_attr_mii_status, @@ -87,6 +117,8 @@ static const struct slave_attribute *slave_attrs[] = { &slave_attr_perm_hwaddr, &slave_attr_queue_id, &slave_attr_ad_aggregator_id, + &slave_attr_ad_actor_oper_port_state, + &slave_attr_ad_partner_oper_port_state, NULL }; |