diff options
author | Girish Moodalbail <girish.moodalbail@oracle.com> | 2017-08-09 04:09:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-08-11 16:45:02 -0400 |
commit | c5ebc4409f2bb2c0b053c204ba197c6b71527eed (patch) | |
tree | 1dc3df096515f9e0c369af693e19fcab3a04002e /drivers/net/geneve.c | |
parent | b50db91987fb1d4288ac8fdb7ba7487b352be6b5 (diff) |
geneve: use netlink_ext_ack for error reporting in rtnl operations
Add extack error messages for failure paths while creating/modifying
geneve devices. Once extack support is added to iproute2, more
meaningful and helpful error messages will be displayed making it easy
for users to discern what went wrong.
Before:
=======
$ ip link add gen1 address 0:1:2:3:4:5:6 type geneve id 200 \
remote 192.168.13.2
RTNETLINK answers: Invalid argument
After:
======
$ ip link add gen1 address 0:1:2:3:4:5:6 type geneve id 200 \
remote 192.168.13.2
Error: Provided link layer address is not Ethernet
Also, netdev_dbg() calls used to log errors associated with Netlink
request have been removed.
Signed-off-by: Girish Moodalbail <girish.moodalbail@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/geneve.c')
-rw-r--r-- | drivers/net/geneve.c | 128 |
1 files changed, 92 insertions, 36 deletions
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 8b8565dd2afb..f6404074b7b0 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c | |||
@@ -1086,21 +1086,33 @@ static int geneve_validate(struct nlattr *tb[], struct nlattr *data[], | |||
1086 | struct netlink_ext_ack *extack) | 1086 | struct netlink_ext_ack *extack) |
1087 | { | 1087 | { |
1088 | if (tb[IFLA_ADDRESS]) { | 1088 | if (tb[IFLA_ADDRESS]) { |
1089 | if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) | 1089 | if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) { |
1090 | NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS], | ||
1091 | "Provided link layer address is not Ethernet"); | ||
1090 | return -EINVAL; | 1092 | return -EINVAL; |
1093 | } | ||
1091 | 1094 | ||
1092 | if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) | 1095 | if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) { |
1096 | NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_ADDRESS], | ||
1097 | "Provided Ethernet address is not unicast"); | ||
1093 | return -EADDRNOTAVAIL; | 1098 | return -EADDRNOTAVAIL; |
1099 | } | ||
1094 | } | 1100 | } |
1095 | 1101 | ||
1096 | if (!data) | 1102 | if (!data) { |
1103 | NL_SET_ERR_MSG(extack, | ||
1104 | "Not enough attributes provided to perform the operation"); | ||
1097 | return -EINVAL; | 1105 | return -EINVAL; |
1106 | } | ||
1098 | 1107 | ||
1099 | if (data[IFLA_GENEVE_ID]) { | 1108 | if (data[IFLA_GENEVE_ID]) { |
1100 | __u32 vni = nla_get_u32(data[IFLA_GENEVE_ID]); | 1109 | __u32 vni = nla_get_u32(data[IFLA_GENEVE_ID]); |
1101 | 1110 | ||
1102 | if (vni >= GENEVE_N_VID) | 1111 | if (vni >= GENEVE_N_VID) { |
1112 | NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_ID], | ||
1113 | "Geneve ID must be lower than 16777216"); | ||
1103 | return -ERANGE; | 1114 | return -ERANGE; |
1115 | } | ||
1104 | } | 1116 | } |
1105 | 1117 | ||
1106 | return 0; | 1118 | return 0; |
@@ -1158,6 +1170,7 @@ static bool geneve_dst_addr_equal(struct ip_tunnel_info *a, | |||
1158 | } | 1170 | } |
1159 | 1171 | ||
1160 | static int geneve_configure(struct net *net, struct net_device *dev, | 1172 | static int geneve_configure(struct net *net, struct net_device *dev, |
1173 | struct netlink_ext_ack *extack, | ||
1161 | const struct ip_tunnel_info *info, | 1174 | const struct ip_tunnel_info *info, |
1162 | bool metadata, bool ipv6_rx_csum) | 1175 | bool metadata, bool ipv6_rx_csum) |
1163 | { | 1176 | { |
@@ -1166,8 +1179,11 @@ static int geneve_configure(struct net *net, struct net_device *dev, | |||
1166 | bool tun_collect_md, tun_on_same_port; | 1179 | bool tun_collect_md, tun_on_same_port; |
1167 | int err, encap_len; | 1180 | int err, encap_len; |
1168 | 1181 | ||
1169 | if (metadata && !is_tnl_info_zero(info)) | 1182 | if (metadata && !is_tnl_info_zero(info)) { |
1183 | NL_SET_ERR_MSG(extack, | ||
1184 | "Device is externally controlled, so attributes (VNI, Port, and so on) must not be specified"); | ||
1170 | return -EINVAL; | 1185 | return -EINVAL; |
1186 | } | ||
1171 | 1187 | ||
1172 | geneve->net = net; | 1188 | geneve->net = net; |
1173 | geneve->dev = dev; | 1189 | geneve->dev = dev; |
@@ -1188,11 +1204,17 @@ static int geneve_configure(struct net *net, struct net_device *dev, | |||
1188 | dev->needed_headroom = encap_len + ETH_HLEN; | 1204 | dev->needed_headroom = encap_len + ETH_HLEN; |
1189 | 1205 | ||
1190 | if (metadata) { | 1206 | if (metadata) { |
1191 | if (tun_on_same_port) | 1207 | if (tun_on_same_port) { |
1208 | NL_SET_ERR_MSG(extack, | ||
1209 | "There can be only one externally controlled device on a destination port"); | ||
1192 | return -EPERM; | 1210 | return -EPERM; |
1211 | } | ||
1193 | } else { | 1212 | } else { |
1194 | if (tun_collect_md) | 1213 | if (tun_collect_md) { |
1214 | NL_SET_ERR_MSG(extack, | ||
1215 | "There already exists an externally controlled device on this destination port"); | ||
1195 | return -EPERM; | 1216 | return -EPERM; |
1217 | } | ||
1196 | } | 1218 | } |
1197 | 1219 | ||
1198 | dst_cache_reset(&geneve->info.dst_cache); | 1220 | dst_cache_reset(&geneve->info.dst_cache); |
@@ -1214,31 +1236,41 @@ static void init_tnl_info(struct ip_tunnel_info *info, __u16 dst_port) | |||
1214 | info->key.tp_dst = htons(dst_port); | 1236 | info->key.tp_dst = htons(dst_port); |
1215 | } | 1237 | } |
1216 | 1238 | ||
1217 | static int geneve_nl2info(struct net_device *dev, struct nlattr *tb[], | 1239 | static int geneve_nl2info(struct nlattr *tb[], struct nlattr *data[], |
1218 | struct nlattr *data[], struct ip_tunnel_info *info, | 1240 | struct netlink_ext_ack *extack, |
1219 | bool *metadata, bool *use_udp6_rx_checksums, | 1241 | struct ip_tunnel_info *info, bool *metadata, |
1220 | bool changelink) | 1242 | bool *use_udp6_rx_checksums, bool changelink) |
1221 | { | 1243 | { |
1222 | if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6]) | 1244 | int attrtype; |
1245 | |||
1246 | if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6]) { | ||
1247 | NL_SET_ERR_MSG(extack, | ||
1248 | "Cannot specify both IPv4 and IPv6 Remote addresses"); | ||
1223 | return -EINVAL; | 1249 | return -EINVAL; |
1250 | } | ||
1224 | 1251 | ||
1225 | if (data[IFLA_GENEVE_REMOTE]) { | 1252 | if (data[IFLA_GENEVE_REMOTE]) { |
1226 | if (changelink && (ip_tunnel_info_af(info) == AF_INET6)) | 1253 | if (changelink && (ip_tunnel_info_af(info) == AF_INET6)) { |
1227 | return -EOPNOTSUPP; | 1254 | attrtype = IFLA_GENEVE_REMOTE; |
1255 | goto change_notsup; | ||
1256 | } | ||
1228 | 1257 | ||
1229 | info->key.u.ipv4.dst = | 1258 | info->key.u.ipv4.dst = |
1230 | nla_get_in_addr(data[IFLA_GENEVE_REMOTE]); | 1259 | nla_get_in_addr(data[IFLA_GENEVE_REMOTE]); |
1231 | 1260 | ||
1232 | if (IN_MULTICAST(ntohl(info->key.u.ipv4.dst))) { | 1261 | if (IN_MULTICAST(ntohl(info->key.u.ipv4.dst))) { |
1233 | netdev_dbg(dev, "multicast remote is unsupported\n"); | 1262 | NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE], |
1263 | "Remote IPv4 address cannot be Multicast"); | ||
1234 | return -EINVAL; | 1264 | return -EINVAL; |
1235 | } | 1265 | } |
1236 | } | 1266 | } |
1237 | 1267 | ||
1238 | if (data[IFLA_GENEVE_REMOTE6]) { | 1268 | if (data[IFLA_GENEVE_REMOTE6]) { |
1239 | #if IS_ENABLED(CONFIG_IPV6) | 1269 | #if IS_ENABLED(CONFIG_IPV6) |
1240 | if (changelink && (ip_tunnel_info_af(info) == AF_INET)) | 1270 | if (changelink && (ip_tunnel_info_af(info) == AF_INET)) { |
1241 | return -EOPNOTSUPP; | 1271 | attrtype = IFLA_GENEVE_REMOTE6; |
1272 | goto change_notsup; | ||
1273 | } | ||
1242 | 1274 | ||
1243 | info->mode = IP_TUNNEL_INFO_IPV6; | 1275 | info->mode = IP_TUNNEL_INFO_IPV6; |
1244 | info->key.u.ipv6.dst = | 1276 | info->key.u.ipv6.dst = |
@@ -1246,16 +1278,20 @@ static int geneve_nl2info(struct net_device *dev, struct nlattr *tb[], | |||
1246 | 1278 | ||
1247 | if (ipv6_addr_type(&info->key.u.ipv6.dst) & | 1279 | if (ipv6_addr_type(&info->key.u.ipv6.dst) & |
1248 | IPV6_ADDR_LINKLOCAL) { | 1280 | IPV6_ADDR_LINKLOCAL) { |
1249 | netdev_dbg(dev, "link-local remote is unsupported\n"); | 1281 | NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6], |
1282 | "Remote IPv6 address cannot be link-local"); | ||
1250 | return -EINVAL; | 1283 | return -EINVAL; |
1251 | } | 1284 | } |
1252 | if (ipv6_addr_is_multicast(&info->key.u.ipv6.dst)) { | 1285 | if (ipv6_addr_is_multicast(&info->key.u.ipv6.dst)) { |
1253 | netdev_dbg(dev, "multicast remote is unsupported\n"); | 1286 | NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6], |
1287 | "Remote IPv6 address cannot be Multicast"); | ||
1254 | return -EINVAL; | 1288 | return -EINVAL; |
1255 | } | 1289 | } |
1256 | info->key.tun_flags |= TUNNEL_CSUM; | 1290 | info->key.tun_flags |= TUNNEL_CSUM; |
1257 | *use_udp6_rx_checksums = true; | 1291 | *use_udp6_rx_checksums = true; |
1258 | #else | 1292 | #else |
1293 | NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_REMOTE6], | ||
1294 | "IPv6 support not enabled in the kernel"); | ||
1259 | return -EPFNOSUPPORT; | 1295 | return -EPFNOSUPPORT; |
1260 | #endif | 1296 | #endif |
1261 | } | 1297 | } |
@@ -1271,8 +1307,10 @@ static int geneve_nl2info(struct net_device *dev, struct nlattr *tb[], | |||
1271 | tvni[2] = vni & 0x000000ff; | 1307 | tvni[2] = vni & 0x000000ff; |
1272 | 1308 | ||
1273 | tunid = vni_to_tunnel_id(tvni); | 1309 | tunid = vni_to_tunnel_id(tvni); |
1274 | if (changelink && (tunid != info->key.tun_id)) | 1310 | if (changelink && (tunid != info->key.tun_id)) { |
1275 | return -EOPNOTSUPP; | 1311 | attrtype = IFLA_GENEVE_ID; |
1312 | goto change_notsup; | ||
1313 | } | ||
1276 | info->key.tun_id = tunid; | 1314 | info->key.tun_id = tunid; |
1277 | } | 1315 | } |
1278 | 1316 | ||
@@ -1285,44 +1323,61 @@ static int geneve_nl2info(struct net_device *dev, struct nlattr *tb[], | |||
1285 | if (data[IFLA_GENEVE_LABEL]) { | 1323 | if (data[IFLA_GENEVE_LABEL]) { |
1286 | info->key.label = nla_get_be32(data[IFLA_GENEVE_LABEL]) & | 1324 | info->key.label = nla_get_be32(data[IFLA_GENEVE_LABEL]) & |
1287 | IPV6_FLOWLABEL_MASK; | 1325 | IPV6_FLOWLABEL_MASK; |
1288 | if (info->key.label && (!(info->mode & IP_TUNNEL_INFO_IPV6))) | 1326 | if (info->key.label && (!(info->mode & IP_TUNNEL_INFO_IPV6))) { |
1327 | NL_SET_ERR_MSG_ATTR(extack, data[IFLA_GENEVE_LABEL], | ||
1328 | "Label attribute only applies for IPv6 Geneve devices"); | ||
1289 | return -EINVAL; | 1329 | return -EINVAL; |
1330 | } | ||
1290 | } | 1331 | } |
1291 | 1332 | ||
1292 | if (data[IFLA_GENEVE_PORT]) { | 1333 | if (data[IFLA_GENEVE_PORT]) { |
1293 | if (changelink) | 1334 | if (changelink) { |
1294 | return -EOPNOTSUPP; | 1335 | attrtype = IFLA_GENEVE_PORT; |
1336 | goto change_notsup; | ||
1337 | } | ||
1295 | info->key.tp_dst = nla_get_be16(data[IFLA_GENEVE_PORT]); | 1338 | info->key.tp_dst = nla_get_be16(data[IFLA_GENEVE_PORT]); |
1296 | } | 1339 | } |
1297 | 1340 | ||
1298 | if (data[IFLA_GENEVE_COLLECT_METADATA]) { | 1341 | if (data[IFLA_GENEVE_COLLECT_METADATA]) { |
1299 | if (changelink) | 1342 | if (changelink) { |
1300 | return -EOPNOTSUPP; | 1343 | attrtype = IFLA_GENEVE_COLLECT_METADATA; |
1344 | goto change_notsup; | ||
1345 | } | ||
1301 | *metadata = true; | 1346 | *metadata = true; |
1302 | } | 1347 | } |
1303 | 1348 | ||
1304 | if (data[IFLA_GENEVE_UDP_CSUM]) { | 1349 | if (data[IFLA_GENEVE_UDP_CSUM]) { |
1305 | if (changelink) | 1350 | if (changelink) { |
1306 | return -EOPNOTSUPP; | 1351 | attrtype = IFLA_GENEVE_UDP_CSUM; |
1352 | goto change_notsup; | ||
1353 | } | ||
1307 | if (nla_get_u8(data[IFLA_GENEVE_UDP_CSUM])) | 1354 | if (nla_get_u8(data[IFLA_GENEVE_UDP_CSUM])) |
1308 | info->key.tun_flags |= TUNNEL_CSUM; | 1355 | info->key.tun_flags |= TUNNEL_CSUM; |
1309 | } | 1356 | } |
1310 | 1357 | ||
1311 | if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) { | 1358 | if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) { |
1312 | if (changelink) | 1359 | if (changelink) { |
1313 | return -EOPNOTSUPP; | 1360 | attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_TX; |
1361 | goto change_notsup; | ||
1362 | } | ||
1314 | if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX])) | 1363 | if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX])) |
1315 | info->key.tun_flags &= ~TUNNEL_CSUM; | 1364 | info->key.tun_flags &= ~TUNNEL_CSUM; |
1316 | } | 1365 | } |
1317 | 1366 | ||
1318 | if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) { | 1367 | if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) { |
1319 | if (changelink) | 1368 | if (changelink) { |
1320 | return -EOPNOTSUPP; | 1369 | attrtype = IFLA_GENEVE_UDP_ZERO_CSUM6_RX; |
1370 | goto change_notsup; | ||
1371 | } | ||
1321 | if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX])) | 1372 | if (nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX])) |
1322 | *use_udp6_rx_checksums = false; | 1373 | *use_udp6_rx_checksums = false; |
1323 | } | 1374 | } |
1324 | 1375 | ||
1325 | return 0; | 1376 | return 0; |
1377 | change_notsup: | ||
1378 | NL_SET_ERR_MSG_ATTR(extack, data[attrtype], | ||
1379 | "Changing VNI, Port, endpoint IP address family, external, and UDP checksum attributes are not supported"); | ||
1380 | return -EOPNOTSUPP; | ||
1326 | } | 1381 | } |
1327 | 1382 | ||
1328 | static int geneve_newlink(struct net *net, struct net_device *dev, | 1383 | static int geneve_newlink(struct net *net, struct net_device *dev, |
@@ -1335,12 +1390,13 @@ static int geneve_newlink(struct net *net, struct net_device *dev, | |||
1335 | int err; | 1390 | int err; |
1336 | 1391 | ||
1337 | init_tnl_info(&info, GENEVE_UDP_PORT); | 1392 | init_tnl_info(&info, GENEVE_UDP_PORT); |
1338 | err = geneve_nl2info(dev, tb, data, &info, &metadata, | 1393 | err = geneve_nl2info(tb, data, extack, &info, &metadata, |
1339 | &use_udp6_rx_checksums, false); | 1394 | &use_udp6_rx_checksums, false); |
1340 | if (err) | 1395 | if (err) |
1341 | return err; | 1396 | return err; |
1342 | 1397 | ||
1343 | return geneve_configure(net, dev, &info, metadata, use_udp6_rx_checksums); | 1398 | return geneve_configure(net, dev, extack, &info, metadata, |
1399 | use_udp6_rx_checksums); | ||
1344 | } | 1400 | } |
1345 | 1401 | ||
1346 | /* Quiesces the geneve device data path for both TX and RX. | 1402 | /* Quiesces the geneve device data path for both TX and RX. |
@@ -1409,7 +1465,7 @@ static int geneve_changelink(struct net_device *dev, struct nlattr *tb[], | |||
1409 | memcpy(&info, &geneve->info, sizeof(info)); | 1465 | memcpy(&info, &geneve->info, sizeof(info)); |
1410 | metadata = geneve->collect_md; | 1466 | metadata = geneve->collect_md; |
1411 | use_udp6_rx_checksums = geneve->use_udp6_rx_checksums; | 1467 | use_udp6_rx_checksums = geneve->use_udp6_rx_checksums; |
1412 | err = geneve_nl2info(dev, tb, data, &info, &metadata, | 1468 | err = geneve_nl2info(tb, data, extack, &info, &metadata, |
1413 | &use_udp6_rx_checksums, true); | 1469 | &use_udp6_rx_checksums, true); |
1414 | if (err) | 1470 | if (err) |
1415 | return err; | 1471 | return err; |
@@ -1536,7 +1592,7 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name, | |||
1536 | return dev; | 1592 | return dev; |
1537 | 1593 | ||
1538 | init_tnl_info(&info, dst_port); | 1594 | init_tnl_info(&info, dst_port); |
1539 | err = geneve_configure(net, dev, &info, true, true); | 1595 | err = geneve_configure(net, dev, NULL, &info, true, true); |
1540 | if (err) { | 1596 | if (err) { |
1541 | free_netdev(dev); | 1597 | free_netdev(dev); |
1542 | return ERR_PTR(err); | 1598 | return ERR_PTR(err); |