On 27/03/2020 11:21, Horatiu Vultur wrote: > Implement netlink interface to configure MRP. The implementation > will do sanity checks over the attributes and then eventually call the MRP > interface. > > Signed-off-by: Horatiu Vultur <horatiu.vultur@xxxxxxxxxxxxx> > --- > net/bridge/br_mrp_netlink.c | 176 ++++++++++++++++++++++++++++++++++++ > 1 file changed, 176 insertions(+) > create mode 100644 net/bridge/br_mrp_netlink.c > Hi Horatiu, > diff --git a/net/bridge/br_mrp_netlink.c b/net/bridge/br_mrp_netlink.c > new file mode 100644 > index 000000000000..043b7f6cddbe > --- /dev/null > +++ b/net/bridge/br_mrp_netlink.c > @@ -0,0 +1,176 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > + > +#include <net/genetlink.h> > + > +#include <uapi/linux/mrp_bridge.h> > +#include "br_private.h" > +#include "br_private_mrp.h" > + > +static int br_mrp_parse_instance(struct net_bridge *br, struct nlattr *attr, > + int cmd) > +{ > + struct br_mrp_instance *instance; > + > + if (nla_len(attr) != sizeof(*instance)) > + return -EINVAL; > + > + instance = nla_data(attr); > + > + if (cmd == RTM_SETLINK) > + return br_mrp_add(br, instance); > + else > + return br_mrp_del(br, instance); > +} > + > +static int br_mrp_parse_port_state(struct net_bridge *br, > + struct net_bridge_port *p, > + struct nlattr *attr) > +{ > + enum br_mrp_port_state_type state; > + > + if (nla_len(attr) != sizeof(u32) || !p) > + return -EINVAL; > + > + state = nla_get_u32(attr); > + > + return br_mrp_set_port_state(p, state); > +} > + > +static int br_mrp_parse_port_role(struct net_bridge *br, > + struct net_bridge_port *p, > + struct nlattr *attr) > +{ > + struct br_mrp_port_role *role; > + > + if (nla_len(attr) != sizeof(*role) || !p) > + return -EINVAL; > + > + role = nla_data(attr); > + > + return br_mrp_set_port_role(p, role->ring_id, role->role); > +} > + > +static int br_mrp_parse_ring_state(struct net_bridge *br, struct nlattr *attr) > +{ > + struct br_mrp_ring_state *state; > + > + if (nla_len(attr) != sizeof(*state)) > + return -EINVAL; > + > + state = nla_data(attr); > + > + return br_mrp_set_ring_state(br, state->ring_id, state->ring_state); > +} > + > +static int br_mrp_parse_ring_role(struct net_bridge *br, struct nlattr *attr) > +{ > + struct br_mrp_ring_role *role; > + > + if (nla_len(attr) != sizeof(*role)) > + return -EINVAL; > + > + role = nla_data(attr); > + > + return br_mrp_set_ring_role(br, role->ring_id, role->ring_role); > +} > + > +static int br_mrp_parse_start_test(struct net_bridge *br, struct nlattr *attr) > +{ > + struct br_mrp_start_test *test; > + > + if (nla_len(attr) != sizeof(*test)) > + return -EINVAL; > + > + test = nla_data(attr); > + > + return br_mrp_start_test(br, test->ring_id, test->interval, > + test->max_miss, test->period); > +} > + > +int br_mrp_parse(struct net_bridge *br, struct net_bridge_port *p, > + struct nlattr *attr, int cmd) > +{ > + struct nlattr *mrp; > + int rem, err; > + > + nla_for_each_nested(mrp, attr, rem) { > + err = 0; > + switch (nla_type(mrp)) { > + case IFLA_BRIDGE_MRP_INSTANCE: > + err = br_mrp_parse_instance(br, mrp, cmd); > + if (err) > + return err; > + break; > + case IFLA_BRIDGE_MRP_PORT_STATE: > + err = br_mrp_parse_port_state(br, p, mrp); > + if (err) > + return err; > + break; > + case IFLA_BRIDGE_MRP_PORT_ROLE: > + err = br_mrp_parse_port_role(br, p, mrp); > + if (err) > + return err; > + break; > + case IFLA_BRIDGE_MRP_RING_STATE: > + err = br_mrp_parse_ring_state(br, mrp); > + if (err) > + return err; > + break; > + case IFLA_BRIDGE_MRP_RING_ROLE: > + err = br_mrp_parse_ring_role(br, mrp); > + if (err) > + return err; > + break; > + case IFLA_BRIDGE_MRP_START_TEST: > + err = br_mrp_parse_start_test(br, mrp); > + if (err) > + return err; > + break; > + } > + } > + > + return 0; > +} All of the above can be implemented via nla_parse_nested() with a proper policy. You don't have to manually check for the attribute size. Then your code follows the netlink normal (e.g. check the bridge netlink handling) of: nla_parse_nested(tb) if (tb[attr]) do_something_with(tb[attr]) ... > + > +void br_mrp_port_open(struct net_device *dev, u8 loc) > +{ > + struct nlattr *af, *mrp; > + struct ifinfomsg *hdr; > + struct nlmsghdr *nlh; > + struct sk_buff *skb; > + int err = -ENOBUFS; > + struct net *net; > + > + net = dev_net(dev); > + > + skb = nlmsg_new(1024, GFP_ATOMIC); Please add a function which calculates the size based on the attribute sizes. > + if (!skb) > + goto errout; > + > + nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*hdr), 0); > + if (!nlh) > + goto errout; > + > + hdr = nlmsg_data(nlh); > + hdr->ifi_family = AF_BRIDGE; > + hdr->__ifi_pad = 0; > + hdr->ifi_type = dev->type; > + hdr->ifi_index = dev->ifindex; > + hdr->ifi_flags = dev_get_flags(dev); > + hdr->ifi_change = 0; > + > + af = nla_nest_start_noflag(skb, IFLA_AF_SPEC); > + mrp = nla_nest_start_noflag(skb, IFLA_BRIDGE_MRP); > + These can return an error which has to be handled. > + nla_put_u32(skb, IFLA_BRIDGE_MRP_RING_OPEN, loc); > + Same for this. > + nla_nest_end(skb, mrp); > + nla_nest_end(skb, af); > + nlmsg_end(skb, nlh); > + > + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); > + return; > +errout: > + rtnl_set_sk_err(net, RTNLGRP_LINK, err); > +} > +EXPORT_SYMBOL(br_mrp_port_open); >