Commit f39925dbde7788cfb96419c0f092b086aa325c0f

Authored by David S. Miller
1 parent 2c8cec5c10

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

... ... @@ -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;