@@ -1294,13 +1294,8 @@ static void rt_del(unsigned hash, struct rtable *rt)
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 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
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 ;
@@ -1325,93 +1317,13 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
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 ));
1332
-
1333
- rthp = & rt_hash_table [hash ].chain ;
1334
-
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
- }
1320
+ peer = inet_getpeer_v4 (daddr , 1 );
1321
+ if (peer ) {
1322
+ peer -> redirect_learned .a4 = new_gw ;
1401
1323
1402
- netevent .old = & rth -> dst ;
1403
- netevent .new = & rt -> dst ;
1404
- call_netevent_notifiers (NETEVENT_REDIRECT ,
1405
- & netevent );
1324
+ inet_putpeer (peer );
1406
1325
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 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
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 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
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 @@ static void rt_init_metrics(struct rtable *rt, struct fib_info *fi)
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 ;
0 commit comments