/* Here, it seems a netdevice has already been allocated for us, and the * hsr_dev_setup routine has been executed. Nice!
*/ staticint hsr_newlink(struct net_device *dev, struct rtnl_newlink_params *params, struct netlink_ext_ack *extack)
{ struct net *link_net = rtnl_newlink_link_net(params); struct net_device *link[2], *interlink = NULL; struct nlattr **data = params->data; enum hsr_version proto_version; unsignedchar multicast_spec;
u8 proto = HSR_PROTOCOL_HSR;
if (!net_eq(link_net, dev_net(dev))) {
NL_SET_ERR_MSG_MOD(extack, "HSR slaves/interlink must be on the same net namespace than HSR link"); return -EINVAL;
}
if (!data) {
NL_SET_ERR_MSG_MOD(extack, "No slave devices specified"); return -EINVAL;
} if (!data[IFLA_HSR_SLAVE1]) {
NL_SET_ERR_MSG_MOD(extack, "Slave1 device not specified"); return -EINVAL;
}
link[0] = __dev_get_by_index(link_net,
nla_get_u32(data[IFLA_HSR_SLAVE1])); if (!link[0]) {
NL_SET_ERR_MSG_MOD(extack, "Slave1 does not exist"); return -EINVAL;
} if (!data[IFLA_HSR_SLAVE2]) {
NL_SET_ERR_MSG_MOD(extack, "Slave2 device not specified"); return -EINVAL;
}
link[1] = __dev_get_by_index(link_net,
nla_get_u32(data[IFLA_HSR_SLAVE2])); if (!link[1]) {
NL_SET_ERR_MSG_MOD(extack, "Slave2 does not exist"); return -EINVAL;
}
if (link[0] == link[1]) {
NL_SET_ERR_MSG_MOD(extack, "Slave1 and Slave2 are same"); return -EINVAL;
}
if (data[IFLA_HSR_INTERLINK])
interlink = __dev_get_by_index(link_net,
nla_get_u32(data[IFLA_HSR_INTERLINK]));
if (interlink && interlink == link[0]) {
NL_SET_ERR_MSG_MOD(extack, "Interlink and Slave1 are the same"); return -EINVAL;
}
if (interlink && interlink == link[1]) {
NL_SET_ERR_MSG_MOD(extack, "Interlink and Slave2 are the same"); return -EINVAL;
}
if (!data[IFLA_HSR_VERSION]) {
proto_version = HSR_V0;
} else { if (proto == HSR_PROTOCOL_PRP) {
NL_SET_ERR_MSG_MOD(extack, "PRP version unsupported"); return -EINVAL;
}
proto_version = nla_get_u8(data[IFLA_HSR_VERSION]); if (proto_version > HSR_V1) {
NL_SET_ERR_MSG_MOD(extack, "Only HSR version 0/1 supported"); return -EINVAL;
}
}
if (proto == HSR_PROTOCOL_PRP) {
proto_version = PRP_V1; if (interlink) {
NL_SET_ERR_MSG_MOD(extack, "Interlink only works with HSR"); return -EINVAL;
}
}
/* This is called if for some node with MAC address addr, we only get frames * over one of the slave interfaces. This would indicate an open network ring * (i.e. a link has failed somewhere).
*/ void hsr_nl_ringerror(struct hsr_priv *hsr, unsignedchar addr[ETH_ALEN], struct hsr_port *port)
{ struct sk_buff *skb; void *msg_head; struct hsr_port *master; int res;
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); if (!skb) goto fail;
fail:
rcu_read_lock();
master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
netdev_warn(master->dev, "Could not send HSR ring error message\n");
rcu_read_unlock();
}
/* This is called when we haven't heard from the node with MAC address addr for * some time (just before the node is removed from the node table/list).
*/ void hsr_nl_nodedown(struct hsr_priv *hsr, unsignedchar addr[ETH_ALEN])
{ struct sk_buff *skb; void *msg_head; struct hsr_port *master; int res;
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); if (!skb) goto fail;
/* HSR_C_GET_NODE_STATUS lets userspace query the internal HSR node table * about the status of a specific node in the network, defined by its MAC * address. * * Input: hsr ifindex, node mac address * Output: hsr ifindex, node mac address (copied from request), * age of latest frame from node over slave 1, slave 2 [ms]
*/ staticint hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
{ /* For receiving */ struct nlattr *na; struct net_device *hsr_dev;
/* For sending */ struct sk_buff *skb_out; void *msg_head; struct hsr_priv *hsr; struct hsr_port *port; unsignedchar hsr_node_addr_b[ETH_ALEN]; int hsr_node_if1_age;
u16 hsr_node_if1_seq; int hsr_node_if2_age;
u16 hsr_node_if2_seq; int addr_b_ifindex; int res;
if (!info) goto invalid;
na = info->attrs[HSR_A_IFINDEX]; if (!na) goto invalid;
na = info->attrs[HSR_A_NODE_ADDR]; if (!na) goto invalid;
rcu_read_lock();
hsr_dev = dev_get_by_index_rcu(genl_info_net(info),
nla_get_u32(info->attrs[HSR_A_IFINDEX])); if (!hsr_dev) goto rcu_unlock; if (!is_hsr_master(hsr_dev)) goto rcu_unlock;
/* Send reply */
skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); if (!skb_out) {
res = -ENOMEM; goto fail;
}
msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid,
info->snd_seq, &hsr_genl_family, 0,
HSR_C_SET_NODE_STATUS); if (!msg_head) {
res = -ENOMEM; goto nla_put_failure;
}
res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex); if (res < 0) goto nla_put_failure;
res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN,
nla_data(info->attrs[HSR_A_NODE_ADDR])); if (res < 0) goto nla_put_failure;
if (addr_b_ifindex > -1) {
res = nla_put(skb_out, HSR_A_NODE_ADDR_B, ETH_ALEN,
hsr_node_addr_b); if (res < 0) goto nla_put_failure;
res = nla_put_u32(skb_out, HSR_A_ADDR_B_IFINDEX,
addr_b_ifindex); if (res < 0) goto nla_put_failure;
}
res = nla_put_u32(skb_out, HSR_A_IF1_AGE, hsr_node_if1_age); if (res < 0) goto nla_put_failure;
res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq); if (res < 0) goto nla_put_failure;
port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A); if (port)
res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX,
port->dev->ifindex); if (res < 0) goto nla_put_failure;
res = nla_put_u32(skb_out, HSR_A_IF2_AGE, hsr_node_if2_age); if (res < 0) goto nla_put_failure;
res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq); if (res < 0) goto nla_put_failure;
port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B); if (port)
res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX,
port->dev->ifindex); if (res < 0) goto nla_put_failure;
nla_put_failure:
kfree_skb(skb_out); /* Fall through */
fail:
rcu_read_unlock(); return res;
}
/* Get a list of MacAddressA of all nodes known to this node (including self).
*/ staticint hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
{ unsignedchar addr[ETH_ALEN]; struct net_device *hsr_dev; struct sk_buff *skb_out; struct hsr_priv *hsr; bool restart = false; struct nlattr *na; void *pos = NULL; void *msg_head; int res;
if (!info) goto invalid;
na = info->attrs[HSR_A_IFINDEX]; if (!na) goto invalid;
rcu_read_lock();
hsr_dev = dev_get_by_index_rcu(genl_info_net(info),
nla_get_u32(info->attrs[HSR_A_IFINDEX])); if (!hsr_dev) goto rcu_unlock; if (!is_hsr_master(hsr_dev)) goto rcu_unlock;
restart: /* Send reply */
skb_out = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!skb_out) {
res = -ENOMEM; goto fail;
}
msg_head = genlmsg_put(skb_out, NETLINK_CB(skb_in).portid,
info->snd_seq, &hsr_genl_family, 0,
HSR_C_SET_NODE_LIST); if (!msg_head) {
res = -ENOMEM; goto nla_put_failure;
}
if (!restart) {
res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex); if (res < 0) goto nla_put_failure;
}
hsr = netdev_priv(hsr_dev);
if (!pos)
pos = hsr_get_next_node(hsr, NULL, addr); while (pos) {
res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr); if (res < 0) { if (res == -EMSGSIZE) {
genlmsg_end(skb_out, msg_head);
genlmsg_unicast(genl_info_net(info), skb_out,
info->snd_portid);
restart = true; goto restart;
} goto nla_put_failure;
}
pos = hsr_get_next_node(hsr, pos, addr);
}
rcu_read_unlock();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.