Commit f39925dbde7788cfb96419c0f092b086aa325c0f
1 parent
2c8cec5c10
Exists in
master
and in
39 other branches
ipv4: Cache learned redirect information in inetpeer.
Note that we do not generate the redirect netevent any longer, because we don't create a new cached route. Instead, once the new neighbour is bound to the cached route, we emit a neigh update event instead. Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 42 additions and 94 deletions Side-by-side Diff
net/ipv4/route.c
... | ... | @@ -1294,13 +1294,8 @@ |
1294 | 1294 | void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, |
1295 | 1295 | __be32 saddr, struct net_device *dev) |
1296 | 1296 | { |
1297 | - int i, k; | |
1298 | 1297 | struct in_device *in_dev = __in_dev_get_rcu(dev); |
1299 | - struct rtable *rth; | |
1300 | - struct rtable __rcu **rthp; | |
1301 | - __be32 skeys[2] = { saddr, 0 }; | |
1302 | - int ikeys[2] = { dev->ifindex, 0 }; | |
1303 | - struct netevent_redirect netevent; | |
1298 | + struct inet_peer *peer; | |
1304 | 1299 | struct net *net; |
1305 | 1300 | |
1306 | 1301 | if (!in_dev) |
... | ... | @@ -1312,9 +1307,6 @@ |
1312 | 1307 | ipv4_is_zeronet(new_gw)) |
1313 | 1308 | goto reject_redirect; |
1314 | 1309 | |
1315 | - if (!rt_caching(net)) | |
1316 | - goto reject_redirect; | |
1317 | - | |
1318 | 1310 | if (!IN_DEV_SHARED_MEDIA(in_dev)) { |
1319 | 1311 | if (!inet_addr_onlink(in_dev, new_gw, old_gw)) |
1320 | 1312 | goto reject_redirect; |
1321 | 1313 | |
1322 | 1314 | |
... | ... | @@ -1325,93 +1317,13 @@ |
1325 | 1317 | goto reject_redirect; |
1326 | 1318 | } |
1327 | 1319 | |
1328 | - for (i = 0; i < 2; i++) { | |
1329 | - for (k = 0; k < 2; k++) { | |
1330 | - unsigned hash = rt_hash(daddr, skeys[i], ikeys[k], | |
1331 | - rt_genid(net)); | |
1320 | + peer = inet_getpeer_v4(daddr, 1); | |
1321 | + if (peer) { | |
1322 | + peer->redirect_learned.a4 = new_gw; | |
1332 | 1323 | |
1333 | - rthp = &rt_hash_table[hash].chain; | |
1324 | + inet_putpeer(peer); | |
1334 | 1325 | |
1335 | - while ((rth = rcu_dereference(*rthp)) != NULL) { | |
1336 | - struct rtable *rt; | |
1337 | - | |
1338 | - if (rth->fl.fl4_dst != daddr || | |
1339 | - rth->fl.fl4_src != skeys[i] || | |
1340 | - rth->fl.oif != ikeys[k] || | |
1341 | - rt_is_input_route(rth) || | |
1342 | - rt_is_expired(rth) || | |
1343 | - !net_eq(dev_net(rth->dst.dev), net)) { | |
1344 | - rthp = &rth->dst.rt_next; | |
1345 | - continue; | |
1346 | - } | |
1347 | - | |
1348 | - if (rth->rt_dst != daddr || | |
1349 | - rth->rt_src != saddr || | |
1350 | - rth->dst.error || | |
1351 | - rth->rt_gateway != old_gw || | |
1352 | - rth->dst.dev != dev) | |
1353 | - break; | |
1354 | - | |
1355 | - dst_hold(&rth->dst); | |
1356 | - | |
1357 | - rt = dst_alloc(&ipv4_dst_ops); | |
1358 | - if (rt == NULL) { | |
1359 | - ip_rt_put(rth); | |
1360 | - return; | |
1361 | - } | |
1362 | - | |
1363 | - /* Copy all the information. */ | |
1364 | - *rt = *rth; | |
1365 | - rt->dst.__use = 1; | |
1366 | - atomic_set(&rt->dst.__refcnt, 1); | |
1367 | - rt->dst.child = NULL; | |
1368 | - if (rt->dst.dev) | |
1369 | - dev_hold(rt->dst.dev); | |
1370 | - rt->dst.obsolete = -1; | |
1371 | - rt->dst.lastuse = jiffies; | |
1372 | - rt->dst.path = &rt->dst; | |
1373 | - rt->dst.neighbour = NULL; | |
1374 | - rt->dst.hh = NULL; | |
1375 | -#ifdef CONFIG_XFRM | |
1376 | - rt->dst.xfrm = NULL; | |
1377 | -#endif | |
1378 | - rt->rt_genid = rt_genid(net); | |
1379 | - rt->rt_flags |= RTCF_REDIRECTED; | |
1380 | - | |
1381 | - /* Gateway is different ... */ | |
1382 | - rt->rt_gateway = new_gw; | |
1383 | - | |
1384 | - /* Redirect received -> path was valid */ | |
1385 | - dst_confirm(&rth->dst); | |
1386 | - | |
1387 | - if (rt->peer) | |
1388 | - atomic_inc(&rt->peer->refcnt); | |
1389 | - if (rt->fi) | |
1390 | - atomic_inc(&rt->fi->fib_clntref); | |
1391 | - | |
1392 | - if (arp_bind_neighbour(&rt->dst) || | |
1393 | - !(rt->dst.neighbour->nud_state & | |
1394 | - NUD_VALID)) { | |
1395 | - if (rt->dst.neighbour) | |
1396 | - neigh_event_send(rt->dst.neighbour, NULL); | |
1397 | - ip_rt_put(rth); | |
1398 | - rt_drop(rt); | |
1399 | - goto do_next; | |
1400 | - } | |
1401 | - | |
1402 | - netevent.old = &rth->dst; | |
1403 | - netevent.new = &rt->dst; | |
1404 | - call_netevent_notifiers(NETEVENT_REDIRECT, | |
1405 | - &netevent); | |
1406 | - | |
1407 | - rt_del(hash, rth); | |
1408 | - if (!rt_intern_hash(hash, rt, &rt, NULL, rt->fl.oif)) | |
1409 | - ip_rt_put(rt); | |
1410 | - goto do_next; | |
1411 | - } | |
1412 | - do_next: | |
1413 | - ; | |
1414 | - } | |
1326 | + atomic_inc(&__rt_peer_genid); | |
1415 | 1327 | } |
1416 | 1328 | return; |
1417 | 1329 | |
... | ... | @@ -1678,6 +1590,31 @@ |
1678 | 1590 | } |
1679 | 1591 | } |
1680 | 1592 | |
1593 | +static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) | |
1594 | +{ | |
1595 | + struct rtable *rt = (struct rtable *) dst; | |
1596 | + __be32 orig_gw = rt->rt_gateway; | |
1597 | + | |
1598 | + dst_confirm(&rt->dst); | |
1599 | + | |
1600 | + neigh_release(rt->dst.neighbour); | |
1601 | + rt->dst.neighbour = NULL; | |
1602 | + | |
1603 | + rt->rt_gateway = peer->redirect_learned.a4; | |
1604 | + if (arp_bind_neighbour(&rt->dst) || | |
1605 | + !(rt->dst.neighbour->nud_state & NUD_VALID)) { | |
1606 | + if (rt->dst.neighbour) | |
1607 | + neigh_event_send(rt->dst.neighbour, NULL); | |
1608 | + rt->rt_gateway = orig_gw; | |
1609 | + return -EAGAIN; | |
1610 | + } else { | |
1611 | + rt->rt_flags |= RTCF_REDIRECTED; | |
1612 | + call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, | |
1613 | + rt->dst.neighbour); | |
1614 | + } | |
1615 | + return 0; | |
1616 | +} | |
1617 | + | |
1681 | 1618 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) |
1682 | 1619 | { |
1683 | 1620 | struct rtable *rt = (struct rtable *) dst; |
... | ... | @@ -1694,6 +1631,12 @@ |
1694 | 1631 | if (peer && peer->pmtu_expires) |
1695 | 1632 | check_peer_pmtu(dst, peer); |
1696 | 1633 | |
1634 | + if (peer && peer->redirect_learned.a4 && | |
1635 | + peer->redirect_learned.a4 != rt->rt_gateway) { | |
1636 | + if (check_peer_redir(dst, peer)) | |
1637 | + return NULL; | |
1638 | + } | |
1639 | + | |
1697 | 1640 | rt->rt_peer_genid = rt_peer_genid(); |
1698 | 1641 | } |
1699 | 1642 | return dst; |
... | ... | @@ -1830,6 +1773,11 @@ |
1830 | 1773 | |
1831 | 1774 | if (peer->pmtu_expires) |
1832 | 1775 | check_peer_pmtu(&rt->dst, peer); |
1776 | + if (peer->redirect_learned.a4 && | |
1777 | + peer->redirect_learned.a4 != rt->rt_gateway) { | |
1778 | + rt->rt_gateway = peer->redirect_learned.a4; | |
1779 | + rt->rt_flags |= RTCF_REDIRECTED; | |
1780 | + } | |
1833 | 1781 | } else { |
1834 | 1782 | if (fi->fib_metrics != (u32 *) dst_default_metrics) { |
1835 | 1783 | rt->fi = fi; |