|
|
049c96 |
From 7bfe1d25875b2fef1cfd679fdd8c4a999928bb80 Mon Sep 17 00:00:00 2001
|
|
|
049c96 |
From: Jakub Sitnicki <jkbs@redhat.com>
|
|
|
049c96 |
Date: Wed, 27 Jul 2016 15:56:19 +0200
|
|
|
049c96 |
Subject: [PATCH] iplink: Check address length via netlink
|
|
|
049c96 |
|
|
|
049c96 |
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1253767
|
|
|
049c96 |
https://bugzilla.redhat.com/show_bug.cgi?id=1271580
|
|
|
049c96 |
Upstream Status: iproute2.git commit 8fe58d5
|
|
|
049c96 |
Conflicts:
|
|
|
049c96 |
* context in iplink_parse_vf() because we don't have
|
|
|
049c96 |
6c5ffb9a2c3d ("iplink: cleanup whitespace and checkpatch issues")
|
|
|
049c96 |
|
|
|
049c96 |
commit 8fe58d58941f440140986f444c3d040b5e350c87
|
|
|
049c96 |
Author: Phil Sutter <phil@nwl.cc>
|
|
|
049c96 |
Date: Thu Jun 16 16:19:40 2016 +0200
|
|
|
049c96 |
|
|
|
049c96 |
iplink: Check address length via netlink
|
|
|
049c96 |
|
|
|
049c96 |
This is a feature which was lost during the conversion to netlink
|
|
|
049c96 |
interface: If the device exists and a user tries to change the link
|
|
|
049c96 |
layer address, query the kernel for the old address first and reject the
|
|
|
049c96 |
new one if sizes differ.
|
|
|
049c96 |
|
|
|
049c96 |
This patch adds the same check when setting VF address by assuming same
|
|
|
049c96 |
length as PF device.
|
|
|
049c96 |
|
|
|
049c96 |
Note that at least for VFs the check can't be done in kernel space since
|
|
|
049c96 |
struct ifla_vf_mac lacks a length field and due to netlink padding the
|
|
|
049c96 |
exact size can't be communicated to the kernel.
|
|
|
049c96 |
|
|
|
049c96 |
Signed-off-by: Phil Sutter <phil@nwl.cc>
|
|
|
049c96 |
---
|
|
|
049c96 |
ip/iplink.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
|
|
|
049c96 |
1 file changed, 50 insertions(+), 2 deletions(-)
|
|
|
049c96 |
|
|
|
049c96 |
diff --git a/ip/iplink.c b/ip/iplink.c
|
|
|
049c96 |
index 7b070f4..a8bcc09 100644
|
|
|
049c96 |
--- a/ip/iplink.c
|
|
|
049c96 |
+++ b/ip/iplink.c
|
|
|
049c96 |
@@ -232,6 +232,36 @@ struct iplink_req {
|
|
|
049c96 |
char buf[1024];
|
|
|
049c96 |
};
|
|
|
049c96 |
|
|
|
049c96 |
+static int nl_get_ll_addr_len(unsigned int dev_index)
|
|
|
049c96 |
+{
|
|
|
049c96 |
+ int len;
|
|
|
049c96 |
+ struct iplink_req req = {
|
|
|
049c96 |
+ .n = {
|
|
|
049c96 |
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
|
|
049c96 |
+ .nlmsg_type = RTM_GETLINK,
|
|
|
049c96 |
+ .nlmsg_flags = NLM_F_REQUEST
|
|
|
049c96 |
+ },
|
|
|
049c96 |
+ .i = {
|
|
|
049c96 |
+ .ifi_family = preferred_family,
|
|
|
049c96 |
+ .ifi_index = dev_index,
|
|
|
049c96 |
+ }
|
|
|
049c96 |
+ };
|
|
|
049c96 |
+ struct rtattr *tb[IFLA_MAX+1];
|
|
|
049c96 |
+
|
|
|
049c96 |
+ if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
|
|
|
049c96 |
+ return -1;
|
|
|
049c96 |
+
|
|
|
049c96 |
+ len = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(req.i));
|
|
|
049c96 |
+ if (len < 0)
|
|
|
049c96 |
+ return -1;
|
|
|
049c96 |
+
|
|
|
049c96 |
+ parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(&req.i), len, NLA_F_NESTED);
|
|
|
049c96 |
+ if (!tb[IFLA_ADDRESS])
|
|
|
049c96 |
+ return -1;
|
|
|
049c96 |
+
|
|
|
049c96 |
+ return RTA_PAYLOAD(tb[IFLA_ADDRESS]);
|
|
|
049c96 |
+}
|
|
|
049c96 |
+
|
|
|
049c96 |
static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
|
|
|
049c96 |
struct iplink_req *req, int dev_index)
|
|
|
049c96 |
{
|
|
|
049c96 |
@@ -269,11 +299,18 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
|
|
|
049c96 |
NEXT_ARG();
|
|
|
049c96 |
if (matches(*argv, "mac") == 0) {
|
|
|
049c96 |
struct ifla_vf_mac ivm = { 0 };
|
|
|
049c96 |
+ int halen = nl_get_ll_addr_len(dev_index);
|
|
|
049c96 |
NEXT_ARG();
|
|
|
049c96 |
ivm.vf = vf;
|
|
|
049c96 |
len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
|
|
|
049c96 |
if (len < 0)
|
|
|
049c96 |
return -1;
|
|
|
049c96 |
+ if (halen > 0 && len != halen) {
|
|
|
049c96 |
+ fprintf(stderr,
|
|
|
049c96 |
+ "Invalid address length %d - must be %d bytes\n",
|
|
|
049c96 |
+ len, halen);
|
|
|
049c96 |
+ return -1;
|
|
|
049c96 |
+ }
|
|
|
049c96 |
addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
|
|
|
049c96 |
} else if (matches(*argv, "vlan") == 0) {
|
|
|
049c96 |
struct ifla_vf_vlan ivv;
|
|
|
049c96 |
@@ -416,6 +453,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
|
|
|
049c96 |
int numrxqueues = -1;
|
|
|
049c96 |
int dev_index = 0;
|
|
|
049c96 |
int link_netnsid = -1;
|
|
|
049c96 |
+ int addr_len = 0;
|
|
|
049c96 |
|
|
|
049c96 |
*group = -1;
|
|
|
049c96 |
ret = argc;
|
|
|
049c96 |
@@ -435,10 +473,10 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
|
|
|
049c96 |
*link = *argv;
|
|
|
049c96 |
} else if (matches(*argv, "address") == 0) {
|
|
|
049c96 |
NEXT_ARG();
|
|
|
049c96 |
- len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
|
|
|
049c96 |
+ addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
|
|
|
049c96 |
if (len < 0)
|
|
|
049c96 |
return -1;
|
|
|
049c96 |
- addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
|
|
|
049c96 |
+ addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, addr_len);
|
|
|
049c96 |
} else if (matches(*argv, "broadcast") == 0 ||
|
|
|
049c96 |
strcmp(*argv, "brd") == 0) {
|
|
|
049c96 |
NEXT_ARG();
|
|
|
049c96 |
@@ -635,6 +673,16 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
|
|
|
049c96 |
argc--; argv++;
|
|
|
049c96 |
}
|
|
|
049c96 |
|
|
|
049c96 |
+ if (dev_index && addr_len) {
|
|
|
049c96 |
+ int halen = nl_get_ll_addr_len(dev_index);
|
|
|
049c96 |
+ if (halen >= 0 && halen != addr_len) {
|
|
|
049c96 |
+ fprintf(stderr,
|
|
|
049c96 |
+ "Invalid address length %d - must be %d bytes\n",
|
|
|
049c96 |
+ addr_len, halen);
|
|
|
049c96 |
+ return -1;
|
|
|
049c96 |
+ }
|
|
|
049c96 |
+ }
|
|
|
049c96 |
+
|
|
|
049c96 |
return ret - argc;
|
|
|
049c96 |
}
|
|
|
049c96 |
|
|
|
049c96 |
--
|
|
|
049c96 |
1.8.3.1
|
|
|
049c96 |
|