Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipvs: add more mcast parameters for the sync daemon

- mcast_group: configure the multicast address, now IPv6
is supported too

- mcast_port: configure the multicast port

- mcast_ttl: configure the multicast TTL/HOP_LIMIT

Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>

authored by

Julian Anastasov and committed by
Simon Horman
d3328817 e4ff6751

+172 -24
+4
include/net/ip_vs.h
··· 847 847 #define IP_VS_DEST_TRASH_PERIOD (120 * HZ) 848 848 849 849 struct ipvs_sync_daemon_cfg { 850 + union nf_inet_addr mcast_group; 850 851 int syncid; 851 852 u16 sync_maxlen; 853 + u16 mcast_port; 854 + u8 mcast_af; 855 + u8 mcast_ttl; 852 856 /* multicast interface name */ 853 857 char mcast_ifn[IP_VS_IFNAME_MAXLEN]; 854 858 };
+4
include/uapi/linux/ip_vs.h
··· 407 407 IPVS_DAEMON_ATTR_MCAST_IFN, /* multicast interface name */ 408 408 IPVS_DAEMON_ATTR_SYNC_ID, /* SyncID we belong to */ 409 409 IPVS_DAEMON_ATTR_SYNC_MAXLEN, /* UDP Payload Size */ 410 + IPVS_DAEMON_ATTR_MCAST_GROUP, /* IPv4 Multicast Address */ 411 + IPVS_DAEMON_ATTR_MCAST_GROUP6, /* IPv6 Multicast Address */ 412 + IPVS_DAEMON_ATTR_MCAST_PORT, /* Multicast Port (base) */ 413 + IPVS_DAEMON_ATTR_MCAST_TTL, /* Multicast TTL */ 410 414 __IPVS_DAEMON_ATTR_MAX, 411 415 }; 412 416
+49 -1
net/netfilter/ipvs/ip_vs_ctl.c
··· 2819 2819 .len = IP_VS_IFNAME_MAXLEN }, 2820 2820 [IPVS_DAEMON_ATTR_SYNC_ID] = { .type = NLA_U32 }, 2821 2821 [IPVS_DAEMON_ATTR_SYNC_MAXLEN] = { .type = NLA_U16 }, 2822 + [IPVS_DAEMON_ATTR_MCAST_GROUP] = { .type = NLA_U32 }, 2823 + [IPVS_DAEMON_ATTR_MCAST_GROUP6] = { .len = sizeof(struct in6_addr) }, 2824 + [IPVS_DAEMON_ATTR_MCAST_PORT] = { .type = NLA_U16 }, 2825 + [IPVS_DAEMON_ATTR_MCAST_TTL] = { .type = NLA_U8 }, 2822 2826 }; 2823 2827 2824 2828 /* Policy used for attributes in nested attribute IPVS_CMD_ATTR_SERVICE */ ··· 3292 3288 if (nla_put_u32(skb, IPVS_DAEMON_ATTR_STATE, state) || 3293 3289 nla_put_string(skb, IPVS_DAEMON_ATTR_MCAST_IFN, c->mcast_ifn) || 3294 3290 nla_put_u32(skb, IPVS_DAEMON_ATTR_SYNC_ID, c->syncid) || 3295 - nla_put_u16(skb, IPVS_DAEMON_ATTR_SYNC_MAXLEN, c->sync_maxlen)) 3291 + nla_put_u16(skb, IPVS_DAEMON_ATTR_SYNC_MAXLEN, c->sync_maxlen) || 3292 + nla_put_u16(skb, IPVS_DAEMON_ATTR_MCAST_PORT, c->mcast_port) || 3293 + nla_put_u8(skb, IPVS_DAEMON_ATTR_MCAST_TTL, c->mcast_ttl)) 3296 3294 goto nla_put_failure; 3295 + #ifdef CONFIG_IP_VS_IPV6 3296 + if (c->mcast_af == AF_INET6) { 3297 + if (nla_put_in6_addr(skb, IPVS_DAEMON_ATTR_MCAST_GROUP6, 3298 + &c->mcast_group.in6)) 3299 + goto nla_put_failure; 3300 + } else 3301 + #endif 3302 + if (c->mcast_af == AF_INET && 3303 + nla_put_in_addr(skb, IPVS_DAEMON_ATTR_MCAST_GROUP, 3304 + c->mcast_group.ip)) 3305 + goto nla_put_failure; 3297 3306 nla_nest_end(skb, nl_daemon); 3298 3307 3299 3308 return 0; ··· 3386 3369 a = attrs[IPVS_DAEMON_ATTR_SYNC_MAXLEN]; 3387 3370 if (a) 3388 3371 c.sync_maxlen = nla_get_u16(a); 3372 + 3373 + a = attrs[IPVS_DAEMON_ATTR_MCAST_GROUP]; 3374 + if (a) { 3375 + c.mcast_af = AF_INET; 3376 + c.mcast_group.ip = nla_get_in_addr(a); 3377 + if (!ipv4_is_multicast(c.mcast_group.ip)) 3378 + return -EINVAL; 3379 + } else { 3380 + a = attrs[IPVS_DAEMON_ATTR_MCAST_GROUP6]; 3381 + if (a) { 3382 + #ifdef CONFIG_IP_VS_IPV6 3383 + int addr_type; 3384 + 3385 + c.mcast_af = AF_INET6; 3386 + c.mcast_group.in6 = nla_get_in6_addr(a); 3387 + addr_type = ipv6_addr_type(&c.mcast_group.in6); 3388 + if (!(addr_type & IPV6_ADDR_MULTICAST)) 3389 + return -EINVAL; 3390 + #else 3391 + return -EAFNOSUPPORT; 3392 + #endif 3393 + } 3394 + } 3395 + 3396 + a = attrs[IPVS_DAEMON_ATTR_MCAST_PORT]; 3397 + if (a) 3398 + c.mcast_port = nla_get_u16(a); 3399 + 3400 + a = attrs[IPVS_DAEMON_ATTR_MCAST_TTL]; 3401 + if (a) 3402 + c.mcast_ttl = nla_get_u8(a); 3389 3403 3390 3404 /* The synchronization protocol is incompatible with mixed family 3391 3405 * services
+115 -23
net/netfilter/ipvs/ip_vs_sync.c
··· 262 262 /* ip_vs_sync_conn entries start here */ 263 263 }; 264 264 265 + union ipvs_sockaddr { 266 + struct sockaddr_in in; 267 + struct sockaddr_in6 in6; 268 + }; 269 + 265 270 struct ip_vs_sync_buff { 266 271 struct list_head list; 267 272 unsigned long firstuse; ··· 1306 1301 /* setsockopt(sock, SOL_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); */ 1307 1302 lock_sock(sk); 1308 1303 inet->mc_loop = loop ? 1 : 0; 1304 + #ifdef CONFIG_IP_VS_IPV6 1305 + if (sk->sk_family == AF_INET6) { 1306 + struct ipv6_pinfo *np = inet6_sk(sk); 1307 + 1308 + /* IPV6_MULTICAST_LOOP */ 1309 + np->mc_loop = loop ? 1 : 0; 1310 + } 1311 + #endif 1309 1312 release_sock(sk); 1310 1313 } 1311 1314 ··· 1327 1314 /* setsockopt(sock, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); */ 1328 1315 lock_sock(sk); 1329 1316 inet->mc_ttl = ttl; 1317 + #ifdef CONFIG_IP_VS_IPV6 1318 + if (sk->sk_family == AF_INET6) { 1319 + struct ipv6_pinfo *np = inet6_sk(sk); 1320 + 1321 + /* IPV6_MULTICAST_HOPS */ 1322 + np->mcast_hops = ttl; 1323 + } 1324 + #endif 1330 1325 release_sock(sk); 1331 1326 } 1332 1327 ··· 1346 1325 /* setsockopt(sock, SOL_IP, IP_MTU_DISCOVER, &val, sizeof(val)); */ 1347 1326 lock_sock(sk); 1348 1327 inet->pmtudisc = val; 1328 + #ifdef CONFIG_IP_VS_IPV6 1329 + if (sk->sk_family == AF_INET6) { 1330 + struct ipv6_pinfo *np = inet6_sk(sk); 1331 + 1332 + /* IPV6_MTU_DISCOVER */ 1333 + np->pmtudisc = val; 1334 + } 1335 + #endif 1349 1336 release_sock(sk); 1350 1337 } 1351 1338 ··· 1376 1347 lock_sock(sk); 1377 1348 inet->mc_index = dev->ifindex; 1378 1349 /* inet->mc_addr = 0; */ 1350 + #ifdef CONFIG_IP_VS_IPV6 1351 + if (sk->sk_family == AF_INET6) { 1352 + struct ipv6_pinfo *np = inet6_sk(sk); 1353 + 1354 + /* IPV6_MULTICAST_IF */ 1355 + np->mcast_oif = dev->ifindex; 1356 + } 1357 + #endif 1379 1358 release_sock(sk); 1380 1359 1381 1360 return 0; ··· 1421 1384 return ret; 1422 1385 } 1423 1386 1387 + #ifdef CONFIG_IP_VS_IPV6 1388 + static int join_mcast_group6(struct sock *sk, struct in6_addr *addr, 1389 + char *ifname) 1390 + { 1391 + struct net *net = sock_net(sk); 1392 + struct net_device *dev; 1393 + int ret; 1394 + 1395 + dev = __dev_get_by_name(net, ifname); 1396 + if (!dev) 1397 + return -ENODEV; 1398 + if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) 1399 + return -EINVAL; 1400 + 1401 + lock_sock(sk); 1402 + ret = ipv6_sock_mc_join(sk, dev->ifindex, addr); 1403 + release_sock(sk); 1404 + 1405 + return ret; 1406 + } 1407 + #endif 1424 1408 1425 1409 static int bind_mcastif_addr(struct socket *sock, char *ifname) 1426 1410 { ··· 1470 1412 return sock->ops->bind(sock, (struct sockaddr*)&sin, sizeof(sin)); 1471 1413 } 1472 1414 1415 + static void get_mcast_sockaddr(union ipvs_sockaddr *sa, int *salen, 1416 + struct ipvs_sync_daemon_cfg *c, int id) 1417 + { 1418 + if (AF_INET6 == c->mcast_af) { 1419 + sa->in6 = (struct sockaddr_in6) { 1420 + .sin6_family = AF_INET6, 1421 + .sin6_port = htons(c->mcast_port + id), 1422 + }; 1423 + sa->in6.sin6_addr = c->mcast_group.in6; 1424 + *salen = sizeof(sa->in6); 1425 + } else { 1426 + sa->in = (struct sockaddr_in) { 1427 + .sin_family = AF_INET, 1428 + .sin_port = htons(c->mcast_port + id), 1429 + }; 1430 + sa->in.sin_addr = c->mcast_group.in; 1431 + *salen = sizeof(sa->in); 1432 + } 1433 + } 1434 + 1473 1435 /* 1474 1436 * Set up sending multicast socket over UDP 1475 1437 */ ··· 1497 1419 { 1498 1420 struct netns_ipvs *ipvs = net_ipvs(net); 1499 1421 /* multicast addr */ 1500 - struct sockaddr_in mcast_addr = { 1501 - .sin_family = AF_INET, 1502 - .sin_port = cpu_to_be16(IP_VS_SYNC_PORT + id), 1503 - .sin_addr.s_addr = cpu_to_be32(IP_VS_SYNC_GROUP), 1504 - }; 1422 + union ipvs_sockaddr mcast_addr; 1505 1423 struct socket *sock; 1506 - int result; 1424 + int result, salen; 1507 1425 1508 1426 /* First create a socket */ 1509 - result = sock_create_kern(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); 1427 + result = sock_create_kern(net, ipvs->mcfg.mcast_af, SOCK_DGRAM, 1428 + IPPROTO_UDP, &sock); 1510 1429 if (result < 0) { 1511 1430 pr_err("Error during creation of socket; terminating\n"); 1512 1431 return ERR_PTR(result); ··· 1515 1440 } 1516 1441 1517 1442 set_mcast_loop(sock->sk, 0); 1518 - set_mcast_ttl(sock->sk, 1); 1443 + set_mcast_ttl(sock->sk, ipvs->mcfg.mcast_ttl); 1519 1444 /* Allow fragmentation if MTU changes */ 1520 1445 set_mcast_pmtudisc(sock->sk, IP_PMTUDISC_DONT); 1521 1446 result = sysctl_sync_sock_size(ipvs); 1522 1447 if (result > 0) 1523 1448 set_sock_size(sock->sk, 1, result); 1524 1449 1525 - result = bind_mcastif_addr(sock, ipvs->mcfg.mcast_ifn); 1450 + if (AF_INET == ipvs->mcfg.mcast_af) 1451 + result = bind_mcastif_addr(sock, ipvs->mcfg.mcast_ifn); 1452 + else 1453 + result = 0; 1526 1454 if (result < 0) { 1527 1455 pr_err("Error binding address of the mcast interface\n"); 1528 1456 goto error; 1529 1457 } 1530 1458 1459 + get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->mcfg, id); 1531 1460 result = sock->ops->connect(sock, (struct sockaddr *) &mcast_addr, 1532 - sizeof(struct sockaddr), 0); 1461 + salen, 0); 1533 1462 if (result < 0) { 1534 1463 pr_err("Error connecting to the multicast addr\n"); 1535 1464 goto error; ··· 1554 1475 { 1555 1476 struct netns_ipvs *ipvs = net_ipvs(net); 1556 1477 /* multicast addr */ 1557 - struct sockaddr_in mcast_addr = { 1558 - .sin_family = AF_INET, 1559 - .sin_port = cpu_to_be16(IP_VS_SYNC_PORT + id), 1560 - .sin_addr.s_addr = cpu_to_be32(IP_VS_SYNC_GROUP), 1561 - }; 1478 + union ipvs_sockaddr mcast_addr; 1562 1479 struct socket *sock; 1563 - int result; 1480 + int result, salen; 1564 1481 1565 1482 /* First create a socket */ 1566 - result = sock_create_kern(net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); 1483 + result = sock_create_kern(net, ipvs->bcfg.mcast_af, SOCK_DGRAM, 1484 + IPPROTO_UDP, &sock); 1567 1485 if (result < 0) { 1568 1486 pr_err("Error during creation of socket; terminating\n"); 1569 1487 return ERR_PTR(result); ··· 1571 1495 if (result > 0) 1572 1496 set_sock_size(sock->sk, 0, result); 1573 1497 1574 - result = sock->ops->bind(sock, (struct sockaddr *) &mcast_addr, 1575 - sizeof(struct sockaddr)); 1498 + get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->bcfg, id); 1499 + result = sock->ops->bind(sock, (struct sockaddr *)&mcast_addr, salen); 1576 1500 if (result < 0) { 1577 1501 pr_err("Error binding to the multicast addr\n"); 1578 1502 goto error; 1579 1503 } 1580 1504 1581 1505 /* join the multicast group */ 1582 - result = join_mcast_group(sock->sk, 1583 - (struct in_addr *) &mcast_addr.sin_addr, 1584 - ipvs->bcfg.mcast_ifn); 1506 + #ifdef CONFIG_IP_VS_IPV6 1507 + if (ipvs->bcfg.mcast_af == AF_INET6) 1508 + result = join_mcast_group6(sock->sk, &mcast_addr.in6.sin6_addr, 1509 + ipvs->bcfg.mcast_ifn); 1510 + else 1511 + #endif 1512 + result = join_mcast_group(sock->sk, &mcast_addr.in.sin_addr, 1513 + ipvs->bcfg.mcast_ifn); 1585 1514 if (result < 0) { 1586 1515 pr_err("Error joining to the multicast group\n"); 1587 1516 goto error; ··· 1802 1721 } else 1803 1722 count = ipvs->threads_mask + 1; 1804 1723 1724 + if (c->mcast_af == AF_UNSPEC) { 1725 + c->mcast_af = AF_INET; 1726 + c->mcast_group.ip = cpu_to_be32(IP_VS_SYNC_GROUP); 1727 + } 1728 + if (!c->mcast_port) 1729 + c->mcast_port = IP_VS_SYNC_PORT; 1730 + if (!c->mcast_ttl) 1731 + c->mcast_ttl = 1; 1732 + 1805 1733 dev = __dev_get_by_name(net, c->mcast_ifn); 1806 1734 if (!dev) { 1807 1735 pr_err("Unknown mcast interface: %s\n", c->mcast_ifn); 1808 1736 return -ENODEV; 1809 1737 } 1810 - hlen = sizeof(struct iphdr) + sizeof(struct udphdr); 1738 + hlen = (AF_INET6 == c->mcast_af) ? 1739 + sizeof(struct ipv6hdr) + sizeof(struct udphdr) : 1740 + sizeof(struct iphdr) + sizeof(struct udphdr); 1811 1741 mtu = (state == IP_VS_STATE_BACKUP) ? 1812 1742 clamp(dev->mtu, 1500U, 65535U) : 1500U; 1813 1743 min_mtu = (state == IP_VS_STATE_BACKUP) ? 1024 : 1;