| @@ -320,26 +320,28 @@ sb_dequeue(struct netns_ipvs *ipvs, struct ipvs_master_sync_state *ms) · 319 unmodified lines |
| 320 | 320 | * Create a new sync buffer for Version 1 proto. |
| 321 | 321 | */ |
| 322 | 322 | static inline struct ip_vs_sync_buff * |
| 323 | | −ip_vs_sync_buff_create(struct netns_ipvs *ipvs) |
| 323 | +ip_vs_sync_buff_create(struct netns_ipvs *ipvs, unsigned int len) |
| 324 | 324 | { |
| 325 | 325 | struct ip_vs_sync_buff *sb; |
| 326 | 326 | |
| 327 | 327 | if (!(sb=kmalloc(sizeof(struct ip_vs_sync_buff), GFP_ATOMIC))) |
| 328 | 328 | return NULL; |
| 329 | 329 | |
| 330 | | − sb->mesg = kmalloc(ipvs->send_mesg_maxlen, GFP_ATOMIC); |
| 330 | + len = max_t(unsigned int, len + sizeof(struct ip_vs_sync_mesg), |
| 331 | + ipvs->mcfg.sync_maxlen); |
| 332 | + sb->mesg = kmalloc(len, GFP_ATOMIC); |
| 331 | 333 | if (!sb->mesg) { |
| 332 | 334 | kfree(sb); |
| 333 | 335 | return NULL; |
| 334 | 336 | } |
| 335 | 337 | sb->mesg->reserved = 0; /* old nr_conns i.e. must be zero now */ |
| 336 | 338 | sb->mesg->version = SYNC_PROTO_VER; |
| 337 | | − sb->mesg->syncid = ipvs->master_syncid; |
| 339 | + sb->mesg->syncid = ipvs->mcfg.syncid; |
| 338 | 340 | sb->mesg->size = htons(sizeof(struct ip_vs_sync_mesg)); |
| 339 | 341 | sb->mesg->nr_conns = 0; |
| 340 | 342 | sb->mesg->spare = 0; |
| 341 | 343 | sb->head = (unsigned char *)sb->mesg + sizeof(struct ip_vs_sync_mesg); |
| 342 | | − sb->end = (unsigned char *)sb->mesg + ipvs->send_mesg_maxlen; |
| 344 | + sb->end = (unsigned char *)sb->mesg + len; |
| 343 | 345 | |
| 344 | 346 | sb->firstuse = jiffies; |
| 345 | 347 | return sb; |
| @@ -402,7 +404,7 @@ select_master_thread_id(struct netns_ipvs *ipvs, struct ip_vs_conn *cp) · 56 unmodified lines |
| 402 | 404 | * Create a new sync buffer for Version 0 proto. |
| 403 | 405 | */ |
| 404 | 406 | static inline struct ip_vs_sync_buff * |
| 405 | | −ip_vs_sync_buff_create_v0(struct netns_ipvs *ipvs) |
| 407 | +ip_vs_sync_buff_create_v0(struct netns_ipvs *ipvs, unsigned int len) |
| 406 | 408 | { |
| 407 | 409 | struct ip_vs_sync_buff *sb; |
| 408 | 410 | struct ip_vs_sync_mesg_v0 *mesg; |
| @@ -410,17 +412,19 @@ ip_vs_sync_buff_create_v0(struct netns_ipvs *ipvs) · 1 unmodified line |
| 410 | 412 | if (!(sb=kmalloc(sizeof(struct ip_vs_sync_buff), GFP_ATOMIC))) |
| 411 | 413 | return NULL; |
| 412 | 414 | |
| 413 | | − sb->mesg = kmalloc(ipvs->send_mesg_maxlen, GFP_ATOMIC); |
| 415 | + len = max_t(unsigned int, len + sizeof(struct ip_vs_sync_mesg_v0), |
| 416 | + ipvs->mcfg.sync_maxlen); |
| 417 | + sb->mesg = kmalloc(len, GFP_ATOMIC); |
| 414 | 418 | if (!sb->mesg) { |
| 415 | 419 | kfree(sb); |
| 416 | 420 | return NULL; |
| 417 | 421 | } |
| 418 | 422 | mesg = (struct ip_vs_sync_mesg_v0 *)sb->mesg; |
| 419 | 423 | mesg->nr_conns = 0; |
| 420 | | − mesg->syncid = ipvs->master_syncid; |
| 424 | + mesg->syncid = ipvs->mcfg.syncid; |
| 421 | 425 | mesg->size = htons(sizeof(struct ip_vs_sync_mesg_v0)); |
| 422 | 426 | sb->head = (unsigned char *)mesg + sizeof(struct ip_vs_sync_mesg_v0); |
| 423 | | − sb->end = (unsigned char *)mesg + ipvs->send_mesg_maxlen; |
| 427 | + sb->end = (unsigned char *)mesg + len; |
| 424 | 428 | sb->firstuse = jiffies; |
| 425 | 429 | return sb; |
| 426 | 430 | } |
| @@ -533,7 +537,7 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp, · 106 unmodified lines |
| 533 | 537 | struct ip_vs_sync_buff *buff; |
| 534 | 538 | struct ipvs_master_sync_state *ms; |
| 535 | 539 | int id; |
| 536 | | − int len; |
| 540 | + unsigned int len; |
| 537 | 541 | |
| 538 | 542 | if (unlikely(cp->af != AF_INET)) |
| 539 | 543 | return; |
| @@ -553,17 +557,19 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp, · 13 unmodified lines |
| 553 | 557 | id = select_master_thread_id(ipvs, cp); |
| 554 | 558 | ms = &ipvs->ms[id]; |
| 555 | 559 | buff = ms->sync_buff; |
| 560 | + len = (cp->flags & IP_VS_CONN_F_SEQ_MASK) ? FULL_CONN_SIZE : |
| 561 | + SIMPLE_CONN_SIZE; |
| 556 | 562 | if (buff) { |
| 557 | 563 | m = (struct ip_vs_sync_mesg_v0 *) buff->mesg; |
| 558 | 564 | /* Send buffer if it is for v1 */ |
| 559 | | − if (!m->nr_conns) { |
| 565 | + if (buff->head + len > buff->end || !m->nr_conns) { |
| 560 | 566 | sb_queue_tail(ipvs, ms); |
| 561 | 567 | ms->sync_buff = NULL; |
| 562 | 568 | buff = NULL; |
| 563 | 569 | } |
| 564 | 570 | } |
| 565 | 571 | if (!buff) { |
| 566 | | − buff = ip_vs_sync_buff_create_v0(ipvs); |
| 572 | + buff = ip_vs_sync_buff_create_v0(ipvs, len); |
| 567 | 573 | if (!buff) { |
| 568 | 574 | spin_unlock_bh(&ipvs->sync_buff_lock); |
| 569 | 575 | pr_err("ip_vs_sync_buff_create failed.\n"); |
| @@ -572,8 +578,6 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp, · 2 unmodified lines |
| 572 | 578 | ms->sync_buff = buff; |
| 573 | 579 | } |
| 574 | 580 | |
| 575 | | − len = (cp->flags & IP_VS_CONN_F_SEQ_MASK) ? FULL_CONN_SIZE : |
| 576 | | − SIMPLE_CONN_SIZE; |
| 577 | 581 | m = (struct ip_vs_sync_mesg_v0 *) buff->mesg; |
| 578 | 582 | s = (struct ip_vs_sync_conn_v0 *) buff->head; |
| 579 | 583 | |
| @@ -597,12 +601,6 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp, · 17 unmodified lines |
| 597 | 601 | m->nr_conns++; |
| 598 | 602 | m->size = htons(ntohs(m->size) + len); |
| 599 | 603 | buff->head += len; |
| 600 | | − |
| 601 | | − /* check if there is a space for next one */ |
| 602 | | − if (buff->head + FULL_CONN_SIZE > buff->end) { |
| 603 | | − sb_queue_tail(ipvs, ms); |
| 604 | | − ms->sync_buff = NULL; |
| 605 | | − } |
| 606 | 604 | spin_unlock_bh(&ipvs->sync_buff_lock); |
| 607 | 605 | |
| 608 | 606 | /* synchronize its controller if it has */ |
| @@ -694,7 +692,7 @@ sloop: · 85 unmodified lines |
| 694 | 692 | } |
| 695 | 693 | |
| 696 | 694 | if (!buff) { |
| 697 | | − buff = ip_vs_sync_buff_create(ipvs); |
| 695 | + buff = ip_vs_sync_buff_create(ipvs, len); |
| 698 | 696 | if (!buff) { |
| 699 | 697 | spin_unlock_bh(&ipvs->sync_buff_lock); |
| 700 | 698 | pr_err("ip_vs_sync_buff_create failed.\n"); |
| @@ -1219,7 +1217,7 @@ static void ip_vs_process_message(struct net *net, __u8 *buffer, · 518 unmodified lines |
| 1219 | 1217 | return; |
| 1220 | 1218 | } |
| 1221 | 1219 | /* SyncID sanity check */ |
| 1222 | | − if (ipvs->backup_syncid != 0 && m2->syncid != ipvs->backup_syncid) { |
| 1220 | + if (ipvs->bcfg.syncid != 0 && m2->syncid != ipvs->bcfg.syncid) { |
| 1223 | 1221 | IP_VS_DBG(7, "BACKUP, Ignoring syncid = %d\n", m2->syncid); |
| 1224 | 1222 | return; |
| 1225 | 1223 | } |
| @@ -1319,6 +1317,17 @@ static void set_mcast_ttl(struct sock *sk, u_char ttl) · 93 unmodified lines |
| 1319 | 1317 | release_sock(sk); |
| 1320 | 1318 | } |
| 1321 | 1319 | |
| 1320 | +/* Control fragmentation of messages */ |
| 1321 | +static void set_mcast_pmtudisc(struct sock *sk, int val) |
| 1322 | +{ |
| 1323 | + struct inet_sock *inet = inet_sk(sk); |
| 1324 | + |
| 1325 | + /* setsockopt(sock, SOL_IP, IP_MTU_DISCOVER, &val, sizeof(val)); */ |
| 1326 | + lock_sock(sk); |
| 1327 | + inet->pmtudisc = val; |
| 1328 | + release_sock(sk); |
| 1329 | +} |
| 1330 | + |
| 1322 | 1331 | /* |
| 1323 | 1332 | * Specifiy default interface for outgoing multicasts |
| 1324 | 1333 | */ |
| @@ -1344,43 +1353,6 @@ static int set_mcast_if(struct sock *sk, char *ifname) · 19 unmodified lines |
| 1344 | 1353 | } |
| 1345 | 1354 | |
| 1346 | 1355 | |
| 1347 | | −/* |
| 1348 | | − * Set the maximum length of sync message according to the |
| 1349 | | − * specified interface's MTU. |
| 1350 | | − */ |
| 1351 | | −static int set_sync_mesg_maxlen(struct net *net, int sync_state) |
| 1352 | | −{ |
| 1353 | | − struct netns_ipvs *ipvs = net_ipvs(net); |
| 1354 | | − struct net_device *dev; |
| 1355 | | − int num; |
| 1356 | | − |
| 1357 | | − if (sync_state == IP_VS_STATE_MASTER) { |
| 1358 | | − dev = __dev_get_by_name(net, ipvs->master_mcast_ifn); |
| 1359 | | − if (!dev) |
| 1360 | | − return -ENODEV; |
| 1361 | | − |
| 1362 | | − num = (dev->mtu - sizeof(struct iphdr) - |
| 1363 | | − sizeof(struct udphdr) - |
| 1364 | | − SYNC_MESG_HEADER_LEN - 20) / SIMPLE_CONN_SIZE; |
| 1365 | | − ipvs->send_mesg_maxlen = SYNC_MESG_HEADER_LEN + |
| 1366 | | − SIMPLE_CONN_SIZE * min(num, MAX_CONNS_PER_SYNCBUFF); |
| 1367 | | − IP_VS_DBG(7, "setting the maximum length of sync sending " |
| 1368 | | − "message %d.\n", ipvs->send_mesg_maxlen); |
| 1369 | | − } else if (sync_state == IP_VS_STATE_BACKUP) { |
| 1370 | | − dev = __dev_get_by_name(net, ipvs->backup_mcast_ifn); |
| 1371 | | − if (!dev) |
| 1372 | | − return -ENODEV; |
| 1373 | | − |
| 1374 | | − ipvs->recv_mesg_maxlen = dev->mtu - |
| 1375 | | − sizeof(struct iphdr) - sizeof(struct udphdr); |
| 1376 | | − IP_VS_DBG(7, "setting the maximum length of sync receiving " |
| 1377 | | − "message %d.\n", ipvs->recv_mesg_maxlen); |
| 1378 | | − } |
| 1379 | | − |
| 1380 | | − return 0; |
| 1381 | | −} |
| 1382 | | − |
| 1383 | | − |
| 1384 | 1356 | /* |
| 1385 | 1357 | * Join a multicast group. |
| 1386 | 1358 | * the group is specified by a class D multicast address 224.0.0.0/8 |
| @@ -1461,7 +1433,7 @@ static struct socket *make_send_sock(struct net *net, int id) · 74 unmodified lines |
| 1461 | 1433 | pr_err("Error during creation of socket; terminating\n"); |
| 1462 | 1434 | return ERR_PTR(result); |
| 1463 | 1435 | } |
| 1464 | | − result = set_mcast_if(sock->sk, ipvs->master_mcast_ifn); |
| 1436 | + result = set_mcast_if(sock->sk, ipvs->mcfg.mcast_ifn); |
| 1465 | 1437 | if (result < 0) { |
| 1466 | 1438 | pr_err("Error setting outbound mcast interface\n"); |
| 1467 | 1439 | goto error; |
| @@ -1469,11 +1441,13 @@ static struct socket *make_send_sock(struct net *net, int id) · 1 unmodified line |
| 1469 | 1441 | |
| 1470 | 1442 | set_mcast_loop(sock->sk, 0); |
| 1471 | 1443 | set_mcast_ttl(sock->sk, 1); |
| 1444 | + /* Allow fragmentation if MTU changes */ |
| 1445 | + set_mcast_pmtudisc(sock->sk, IP_PMTUDISC_DONT); |
| 1472 | 1446 | result = sysctl_sync_sock_size(ipvs); |
| 1473 | 1447 | if (result > 0) |
| 1474 | 1448 | set_sock_size(sock->sk, 1, result); |
| 1475 | 1449 | |
| 1476 | | − result = bind_mcastif_addr(sock, ipvs->master_mcast_ifn); |
| 1450 | + result = bind_mcastif_addr(sock, ipvs->mcfg.mcast_ifn); |
| 1477 | 1451 | if (result < 0) { |
| 1478 | 1452 | pr_err("Error binding address of the mcast interface\n"); |
| 1479 | 1453 | goto error; |
| @@ -1531,7 +1505,7 @@ static struct socket *make_receive_sock(struct net *net, int id) · 51 unmodified lines |
| 1531 | 1505 | /* join the multicast group */ |
| 1532 | 1506 | result = join_mcast_group(sock->sk, |
| 1533 | 1507 | (struct in_addr *) &mcast_addr.sin_addr, |
| 1534 | | − ipvs->backup_mcast_ifn); |
| 1508 | + ipvs->bcfg.mcast_ifn); |
| 1535 | 1509 | if (result < 0) { |
| 1536 | 1510 | pr_err("Error joining to the multicast group\n"); |
| 1537 | 1511 | goto error; |
| @@ -1639,7 +1613,7 @@ static int sync_thread_master(void *data) · 101 unmodified lines |
| 1639 | 1613 | |
| 1640 | 1614 | pr_info("sync thread started: state = MASTER, mcast_ifn = %s, " |
| 1641 | 1615 | "syncid = %d, id = %d\n", |
| 1642 | | − ipvs->master_mcast_ifn, ipvs->master_syncid, tinfo->id); |
| 1616 | + ipvs->mcfg.mcast_ifn, ipvs->mcfg.syncid, tinfo->id); |
| 1643 | 1617 | |
| 1644 | 1618 | for (;;) { |
| 1645 | 1619 | sb = next_sync_buff(ipvs, ms); |
| @@ -1693,7 +1667,7 @@ static int sync_thread_backup(void *data) · 47 unmodified lines |
| 1693 | 1667 | |
| 1694 | 1668 | pr_info("sync thread started: state = BACKUP, mcast_ifn = %s, " |
| 1695 | 1669 | "syncid = %d, id = %d\n", |
| 1696 | | − ipvs->backup_mcast_ifn, ipvs->backup_syncid, tinfo->id); |
| 1670 | + ipvs->bcfg.mcast_ifn, ipvs->bcfg.syncid, tinfo->id); |
| 1697 | 1671 | |
| 1698 | 1672 | while (!kthread_should_stop()) { |
| 1699 | 1673 | wait_event_interruptible(*sk_sleep(tinfo->sock->sk), |
| @@ -1703,7 +1677,7 @@ static int sync_thread_backup(void *data) · 3 unmodified lines |
| 1703 | 1677 | /* do we have data now? */ |
| 1704 | 1678 | while (!skb_queue_empty(&(tinfo->sock->sk->sk_receive_queue))) { |
| 1705 | 1679 | len = ip_vs_receive(tinfo->sock, tinfo->buf, |
| 1706 | | − ipvs->recv_mesg_maxlen); |
| 1680 | + ipvs->bcfg.sync_maxlen); |
| 1707 | 1681 | if (len <= 0) { |
| 1708 | 1682 | if (len != -EAGAIN) |
| 1709 | 1683 | pr_err("receiving message error\n"); |
| @@ -1723,16 +1697,19 @@ static int sync_thread_backup(void *data) · 13 unmodified lines |
| 1723 | 1697 | } |
| 1724 | 1698 | |
| 1725 | 1699 | |
| 1726 | | −int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid) |
| 1700 | +int start_sync_thread(struct net *net, struct ipvs_sync_daemon_cfg *c, |
| 1701 | + int state) |
| 1727 | 1702 | { |
| 1728 | 1703 | struct ip_vs_sync_thread_data *tinfo; |
| 1729 | 1704 | struct task_struct **array = NULL, *task; |
| 1730 | 1705 | struct socket *sock; |
| 1731 | 1706 | struct netns_ipvs *ipvs = net_ipvs(net); |
| 1707 | + struct net_device *dev; |
| 1732 | 1708 | char *name; |
| 1733 | 1709 | int (*threadfn)(void *data); |
| 1734 | | − int id, count; |
| 1710 | + int id, count, hlen; |
| 1735 | 1711 | int result = -ENOMEM; |
| 1712 | + u16 mtu, min_mtu; |
| 1736 | 1713 | |
| 1737 | 1714 | IP_VS_DBG(7, "%s(): pid %d\n", __func__, task_pid_nr(current)); |
| 1738 | 1715 | IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %Zd bytes\n", |
| @@ -1744,22 +1721,35 @@ int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid) · 5 unmodified lines |
| 1744 | 1721 | } else |
| 1745 | 1722 | count = ipvs->threads_mask + 1; |
| 1746 | 1723 | |
| 1724 | + dev = __dev_get_by_name(net, c->mcast_ifn); |
| 1725 | + if (!dev) { |
| 1726 | + pr_err("Unknown mcast interface: %s\n", c->mcast_ifn); |
| 1727 | + return -ENODEV; |
| 1728 | + } |
| 1729 | + hlen = sizeof(struct iphdr) + sizeof(struct udphdr); |
| 1730 | + mtu = (state == IP_VS_STATE_BACKUP) ? |
| 1731 | + clamp(dev->mtu, 1500U, 65535U) : 1500U; |
| 1732 | + min_mtu = (state == IP_VS_STATE_BACKUP) ? 1024 : 1; |
| 1733 | + |
| 1734 | + if (c->sync_maxlen) |
| 1735 | + c->sync_maxlen = clamp_t(unsigned int, |
| 1736 | + c->sync_maxlen, min_mtu, |
| 1737 | + 65535 - hlen); |
| 1738 | + else |
| 1739 | + c->sync_maxlen = mtu - hlen; |
| 1740 | + |
| 1747 | 1741 | if (state == IP_VS_STATE_MASTER) { |
| 1748 | 1742 | if (ipvs->ms) |
| 1749 | 1743 | return -EEXIST; |
| 1750 | 1744 | |
| 1751 | | − strlcpy(ipvs->master_mcast_ifn, mcast_ifn, |
| 1752 | | − sizeof(ipvs->master_mcast_ifn)); |
| 1753 | | − ipvs->master_syncid = syncid; |
| 1745 | + ipvs->mcfg = *c; |
| 1754 | 1746 | name = "ipvs-m:%d:%d"; |
| 1755 | 1747 | threadfn = sync_thread_master; |
| 1756 | 1748 | } else if (state == IP_VS_STATE_BACKUP) { |
| 1757 | 1749 | if (ipvs->backup_threads) |
| 1758 | 1750 | return -EEXIST; |
| 1759 | 1751 | |
| 1760 | | − strlcpy(ipvs->backup_mcast_ifn, mcast_ifn, |
| 1761 | | − sizeof(ipvs->backup_mcast_ifn)); |
| 1762 | | − ipvs->backup_syncid = syncid; |
| 1752 | + ipvs->bcfg = *c; |
| 1763 | 1753 | name = "ipvs-b:%d:%d"; |
| 1764 | 1754 | threadfn = sync_thread_backup; |
| 1765 | 1755 | } else { |
| @@ -1787,7 +1777,6 @@ int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid) · 21 unmodified lines |
| 1787 | 1777 | if (!array) |
| 1788 | 1778 | goto out; |
| 1789 | 1779 | } |
| 1790 | | − set_sync_mesg_maxlen(net, state); |
| 1791 | 1780 | |
| 1792 | 1781 | tinfo = NULL; |
| 1793 | 1782 | for (id = 0; id < count; id++) { |
| @@ -1805,7 +1794,7 @@ int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid) · 11 unmodified lines |
| 1805 | 1794 | tinfo->net = net; |
| 1806 | 1795 | tinfo->sock = sock; |
| 1807 | 1796 | if (state == IP_VS_STATE_BACKUP) { |
| 1808 | | − tinfo->buf = kmalloc(ipvs->recv_mesg_maxlen, |
| 1797 | + tinfo->buf = kmalloc(ipvs->bcfg.sync_maxlen, |
| 1809 | 1798 | GFP_KERNEL); |
| 1810 | 1799 | if (!tinfo->buf) |
| 1811 | 1800 | goto outtinfo; |