lib/route: allow override of message type during link change

When rtnl_link_build_change_request() builds a change request,
it sets the message type to RTM_NEWLINK by default. If the
request fails, it changes the type to RTM_SETLINK, and resubmits.

For some address families, this will result in a requested change
never being applied by the kernel. An exmaple of this is the Linux
bridge. When a netlink message of type RTM_NEWLINK is recieved,
rather than failing, it simply ignores the message and does not
return a failure.

To fix this, this patch implements an override for address
families that require it. The override can be set when an address
family registers itself in libnl.

This patch adds ao_override_rtm to the rtnl_link_af_ops structure.
This patch adds a static function named af_request_type.
This patch modifies rtnl_link_build_change_request to call
  af_request_type to properly set the request type if an address
  family wishes to override.

Signed-off-by: Jef Oliver <jef.oliver@intel.com>
Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
Jef Oliver 2016-08-26 19:19:49 -07:00 committed by Thomas Haller
parent 746bbba3e5
commit 5860c205d4
2 changed files with 23 additions and 2 deletions

View File

@ -146,6 +146,14 @@ struct rtnl_link_af_ops
*/
int (*ao_compare)(struct rtnl_link *,
struct rtnl_link *, int, uint32_t, int);
/* RTM_NEWLINK override
*
* Called if a change link request is set to the kernel. If this is set
* to anything other than zero, RTM_NEWLINK will be overriden with
* RTM_SETLINK when rtnl_link_build_change_request() is called.
*/
const int ao_override_rtm;
};
extern struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(unsigned int);

View File

@ -108,6 +108,17 @@ static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
return 0;
}
static int af_request_type(int af_type)
{
struct rtnl_link_af_ops *ops;
ops = rtnl_link_af_ops_lookup(af_type);
if (ops && ops->ao_override_rtm)
return RTM_SETLINK;
return RTM_NEWLINK;
}
static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
void *data, void *arg)
{
@ -1576,7 +1587,7 @@ int rtnl_link_build_change_request(struct rtnl_link *orig,
.ifi_family = orig->l_family,
.ifi_index = orig->l_index,
};
int err;
int err, rt;
if (changes->ce_mask & LINK_ATTR_FLAGS) {
ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
@ -1596,7 +1607,9 @@ int rtnl_link_build_change_request(struct rtnl_link *orig,
!strcmp(orig->l_name, changes->l_name))
changes->ce_mask &= ~LINK_ATTR_IFNAME;
if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
rt = af_request_type(orig->l_family);
if ((err = build_link_msg(rt, &ifi, changes, flags, result)) < 0)
goto errout;
return 0;