700-multiple_default_gateways.patch 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314
  1. Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ip_nat.h
  2. ===================================================================
  3. --- linux-2.4.35.4.orig/include/linux/netfilter_ipv4/ip_nat.h
  4. +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ip_nat.h
  5. @@ -121,5 +121,13 @@ extern int ip_nat_used_tuple(const struc
  6. extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
  7. u_int32_t newval,
  8. u_int16_t oldcheck);
  9. +
  10. +/* Call input routing for SNAT-ed traffic */
  11. +extern unsigned int ip_nat_route_input(unsigned int hooknum,
  12. + struct sk_buff **pskb,
  13. + const struct net_device *in,
  14. + const struct net_device *out,
  15. + int (*okfn)(struct sk_buff *));
  16. +
  17. #endif /*__KERNEL__*/
  18. #endif
  19. Index: linux-2.4.35.4/include/linux/rtnetlink.h
  20. ===================================================================
  21. --- linux-2.4.35.4.orig/include/linux/rtnetlink.h
  22. +++ linux-2.4.35.4/include/linux/rtnetlink.h
  23. @@ -234,6 +234,8 @@ struct rtnexthop
  24. #define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
  25. #define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
  26. #define RTNH_F_ONLINK 4 /* Gateway is forced on link */
  27. +#define RTNH_F_SUSPECT 8 /* We don't know the real state */
  28. +#define RTNH_F_BADSTATE (RTNH_F_DEAD | RTNH_F_SUSPECT)
  29. /* Macros to handle hexthops */
  30. Index: linux-2.4.35.4/include/net/ip_fib.h
  31. ===================================================================
  32. --- linux-2.4.35.4.orig/include/net/ip_fib.h
  33. +++ linux-2.4.35.4/include/net/ip_fib.h
  34. @@ -162,7 +162,8 @@ static inline int fib_lookup(const struc
  35. static inline void fib_select_default(const struct rt_key *key, struct fib_result *res)
  36. {
  37. - if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
  38. + if ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
  39. + FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)
  40. main_table->tb_select_default(main_table, key, res);
  41. }
  42. @@ -174,6 +175,7 @@ extern struct fib_table * fib_tables[RT_
  43. extern int fib_lookup(const struct rt_key *key, struct fib_result *res);
  44. extern struct fib_table *__fib_new_table(int id);
  45. extern void fib_rule_put(struct fib_rule *r);
  46. +extern int fib_result_table(struct fib_result *res);
  47. static inline struct fib_table *fib_get_table(int id)
  48. {
  49. @@ -275,5 +277,6 @@ static inline void fib_res_put(struct fi
  50. #endif
  51. }
  52. +extern rwlock_t fib_nhflags_lock;
  53. #endif /* _NET_FIB_H */
  54. Index: linux-2.4.35.4/include/net/route.h
  55. ===================================================================
  56. --- linux-2.4.35.4.orig/include/net/route.h
  57. +++ linux-2.4.35.4/include/net/route.h
  58. @@ -49,6 +49,8 @@ struct rt_key
  59. {
  60. __u32 dst;
  61. __u32 src;
  62. + __u32 lsrc;
  63. + __u32 gw;
  64. int iif;
  65. int oif;
  66. #ifdef CONFIG_IP_ROUTE_FWMARK
  67. @@ -128,6 +130,7 @@ extern void ip_rt_advice(struct rtable
  68. extern void rt_cache_flush(int how);
  69. extern int ip_route_output_key(struct rtable **, const struct rt_key *key);
  70. extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
  71. +extern int ip_route_input_lookup(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin, u32 lsrc);
  72. extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
  73. extern void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu);
  74. extern void ip_rt_send_redirect(struct sk_buff *skb);
  75. @@ -148,6 +151,15 @@ static inline int ip_route_output(struct
  76. }
  77. +static inline int
  78. +ip_route_output_lookup(struct rtable **rp,
  79. + u32 daddr, u32 saddr, u32 tos, int oif, u32 gw)
  80. +{
  81. + struct rt_key key = { dst:daddr, src:saddr, gw:gw, oif:oif, tos:tos };
  82. +
  83. + return ip_route_output_key(rp, &key);
  84. +}
  85. +
  86. static inline void ip_rt_put(struct rtable * rt)
  87. {
  88. if (rt)
  89. Index: linux-2.4.35.4/net/ipv4/fib_frontend.c
  90. ===================================================================
  91. --- linux-2.4.35.4.orig/net/ipv4/fib_frontend.c
  92. +++ linux-2.4.35.4/net/ipv4/fib_frontend.c
  93. @@ -54,6 +54,8 @@
  94. struct fib_table *local_table;
  95. struct fib_table *main_table;
  96. +#define FIB_RES_TABLE(r) (RT_TABLE_MAIN)
  97. +
  98. #else
  99. #define RT_TABLE_MIN 1
  100. @@ -71,6 +73,7 @@ struct fib_table *__fib_new_table(int id
  101. return tb;
  102. }
  103. +#define FIB_RES_TABLE(r) (fib_result_table(r))
  104. #endif /* CONFIG_IP_MULTIPLE_TABLES */
  105. @@ -209,6 +212,9 @@ int fib_validate_source(u32 src, u32 dst
  106. struct in_device *in_dev;
  107. struct rt_key key;
  108. struct fib_result res;
  109. + int table;
  110. + unsigned char prefixlen;
  111. + unsigned char scope;
  112. int no_addr, rpf;
  113. int ret;
  114. @@ -216,6 +222,7 @@ int fib_validate_source(u32 src, u32 dst
  115. key.src = dst;
  116. key.tos = tos;
  117. key.oif = 0;
  118. + key.gw = 0;
  119. key.iif = oif;
  120. key.scope = RT_SCOPE_UNIVERSE;
  121. @@ -237,31 +244,35 @@ int fib_validate_source(u32 src, u32 dst
  122. goto e_inval_res;
  123. *spec_dst = FIB_RES_PREFSRC(res);
  124. fib_combine_itag(itag, &res);
  125. -#ifdef CONFIG_IP_ROUTE_MULTIPATH
  126. - if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
  127. -#else
  128. if (FIB_RES_DEV(res) == dev)
  129. -#endif
  130. {
  131. ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
  132. fib_res_put(&res);
  133. return ret;
  134. }
  135. + table = FIB_RES_TABLE(&res);
  136. + prefixlen = res.prefixlen;
  137. + scope = res.scope;
  138. fib_res_put(&res);
  139. if (no_addr)
  140. goto last_resort;
  141. - if (rpf)
  142. - goto e_inval;
  143. key.oif = dev->ifindex;
  144. ret = 0;
  145. if (fib_lookup(&key, &res) == 0) {
  146. - if (res.type == RTN_UNICAST) {
  147. + if (res.type == RTN_UNICAST &&
  148. + ((table == FIB_RES_TABLE(&res) &&
  149. + res.prefixlen >= prefixlen && res.scope >= scope) ||
  150. + !rpf)) {
  151. *spec_dst = FIB_RES_PREFSRC(res);
  152. ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
  153. + fib_res_put(&res);
  154. + return ret;
  155. }
  156. fib_res_put(&res);
  157. }
  158. + if (rpf)
  159. + goto e_inval;
  160. return ret;
  161. last_resort:
  162. @@ -579,9 +590,7 @@ static int fib_inetaddr_event(struct not
  163. switch (event) {
  164. case NETDEV_UP:
  165. fib_add_ifaddr(ifa);
  166. -#ifdef CONFIG_IP_ROUTE_MULTIPATH
  167. fib_sync_up(ifa->ifa_dev->dev);
  168. -#endif
  169. rt_cache_flush(-1);
  170. break;
  171. case NETDEV_DOWN:
  172. @@ -617,9 +626,7 @@ static int fib_netdev_event(struct notif
  173. for_ifa(in_dev) {
  174. fib_add_ifaddr(ifa);
  175. } endfor_ifa(in_dev);
  176. -#ifdef CONFIG_IP_ROUTE_MULTIPATH
  177. fib_sync_up(dev);
  178. -#endif
  179. rt_cache_flush(-1);
  180. break;
  181. case NETDEV_DOWN:
  182. Index: linux-2.4.35.4/net/ipv4/fib_hash.c
  183. ===================================================================
  184. --- linux-2.4.35.4.orig/net/ipv4/fib_hash.c
  185. +++ linux-2.4.35.4/net/ipv4/fib_hash.c
  186. @@ -71,6 +71,7 @@ struct fib_node
  187. struct fib_info *fn_info;
  188. #define FIB_INFO(f) ((f)->fn_info)
  189. fn_key_t fn_key;
  190. + int fn_last_dflt;
  191. u8 fn_tos;
  192. u8 fn_type;
  193. u8 fn_scope;
  194. @@ -336,72 +337,123 @@ out:
  195. return err;
  196. }
  197. -static int fn_hash_last_dflt=-1;
  198. -
  199. -static int fib_detect_death(struct fib_info *fi, int order,
  200. - struct fib_info **last_resort, int *last_idx)
  201. +static int fib_detect_death(struct fib_info *fi, int order, int last_dflt,
  202. + struct fib_info **last_resort, int *last_idx,
  203. + int *last_nhsel, const struct rt_key *key)
  204. {
  205. struct neighbour *n;
  206. - int state = NUD_NONE;
  207. + int nhsel;
  208. + int state;
  209. + struct fib_nh * nh;
  210. + u32 dst;
  211. + int flag, dead = 1;
  212. +
  213. + /* change_nexthops(fi) { */
  214. + for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) {
  215. + if (key->oif && key->oif != nh->nh_oif)
  216. + continue;
  217. + if (key->gw && key->gw != nh->nh_gw && nh->nh_gw &&
  218. + nh->nh_scope == RT_SCOPE_LINK)
  219. + continue;
  220. + if (nh->nh_flags & RTNH_F_DEAD)
  221. + continue;
  222. - n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
  223. - if (n) {
  224. - state = n->nud_state;
  225. - neigh_release(n);
  226. + flag = 0;
  227. + if (nh->nh_dev->flags & IFF_NOARP) {
  228. + dead = 0;
  229. + goto setfl;
  230. + }
  231. +
  232. + dst = nh->nh_gw;
  233. + if (!nh->nh_gw || nh->nh_scope != RT_SCOPE_LINK)
  234. + dst = key->dst;
  235. +
  236. + state = NUD_NONE;
  237. + n = neigh_lookup(&arp_tbl, &dst, nh->nh_dev);
  238. + if (n) {
  239. + state = n->nud_state;
  240. + neigh_release(n);
  241. + }
  242. + if (state==NUD_REACHABLE ||
  243. + ((state&NUD_VALID) && order != last_dflt)) {
  244. + dead = 0;
  245. + goto setfl;
  246. + }
  247. + if (!(state&NUD_VALID))
  248. + flag = 1;
  249. + if (!dead)
  250. + goto setfl;
  251. + if ((state&NUD_VALID) ||
  252. + (*last_idx<0 && order >= last_dflt)) {
  253. + *last_resort = fi;
  254. + *last_idx = order;
  255. + *last_nhsel = nhsel;
  256. + }
  257. +
  258. + setfl:
  259. +
  260. + read_lock_bh(&fib_nhflags_lock);
  261. + if (flag)
  262. + nh->nh_flags |= RTNH_F_SUSPECT;
  263. + else
  264. + nh->nh_flags &= ~RTNH_F_SUSPECT;
  265. + read_unlock_bh(&fib_nhflags_lock);
  266. }
  267. - if (state==NUD_REACHABLE)
  268. - return 0;
  269. - if ((state&NUD_VALID) && order != fn_hash_last_dflt)
  270. - return 0;
  271. - if ((state&NUD_VALID) ||
  272. - (*last_idx<0 && order > fn_hash_last_dflt)) {
  273. - *last_resort = fi;
  274. - *last_idx = order;
  275. - }
  276. - return 1;
  277. + /* } endfor_nexthops(fi) */
  278. +
  279. + return dead;
  280. }
  281. static void
  282. fn_hash_select_default(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)
  283. {
  284. - int order, last_idx;
  285. - struct fib_node *f;
  286. + int order, last_idx, last_dflt, last_nhsel;
  287. + struct fib_node *f, *first_node;
  288. struct fib_info *fi = NULL;
  289. struct fib_info *last_resort;
  290. struct fn_hash *t = (struct fn_hash*)tb->tb_data;
  291. - struct fn_zone *fz = t->fn_zones[0];
  292. + struct fn_zone *fz = t->fn_zones[res->prefixlen];
  293. + fn_key_t k;
  294. if (fz == NULL)
  295. return;
  296. + k = fz_key(key->dst, fz);
  297. + last_dflt = -2;
  298. + first_node = NULL;
  299. last_idx = -1;
  300. last_resort = NULL;
  301. + last_nhsel = 0;
  302. order = -1;
  303. read_lock(&fib_hash_lock);
  304. - for (f = fz->fz_hash[0]; f; f = f->fn_next) {
  305. + for (f = fz_chain(k, fz); f; f = f->fn_next) {
  306. struct fib_info *next_fi = FIB_INFO(f);
  307. - if ((f->fn_state&FN_S_ZOMBIE) ||
  308. + if (!fn_key_eq(k, f->fn_key) ||
  309. + (f->fn_state&FN_S_ZOMBIE) ||
  310. f->fn_scope != res->scope ||
  311. +#ifdef CONFIG_IP_ROUTE_TOS
  312. + (f->fn_tos && f->fn_tos != key->tos) ||
  313. +#endif
  314. f->fn_type != RTN_UNICAST)
  315. continue;
  316. if (next_fi->fib_priority > res->fi->fib_priority)
  317. break;
  318. - if (!next_fi->fib_nh[0].nh_gw || next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
  319. - continue;
  320. f->fn_state |= FN_S_ACCESSED;
  321. - if (fi == NULL) {
  322. - if (next_fi != res->fi)
  323. - break;
  324. - } else if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
  325. + if (!first_node) {
  326. + last_dflt = f->fn_last_dflt;
  327. + first_node = f;
  328. + }
  329. + if (fi && !fib_detect_death(fi, order, last_dflt,
  330. + &last_resort, &last_idx, &last_nhsel, key)) {
  331. if (res->fi)
  332. fib_info_put(res->fi);
  333. res->fi = fi;
  334. atomic_inc(&fi->fib_clntref);
  335. - fn_hash_last_dflt = order;
  336. + first_node->fn_last_dflt = order;
  337. goto out;
  338. }
  339. fi = next_fi;
  340. @@ -409,16 +461,25 @@ fn_hash_select_default(struct fib_table
  341. }
  342. if (order<=0 || fi==NULL) {
  343. - fn_hash_last_dflt = -1;
  344. + if (fi && fi->fib_nhs > 1 &&
  345. + fib_detect_death(fi, order, last_dflt,
  346. + &last_resort, &last_idx, &last_nhsel, key) &&
  347. + last_resort == fi) {
  348. + read_lock_bh(&fib_nhflags_lock);
  349. + fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
  350. + read_unlock_bh(&fib_nhflags_lock);
  351. + }
  352. + if (first_node) first_node->fn_last_dflt = -1;
  353. goto out;
  354. }
  355. - if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
  356. + if (!fib_detect_death(fi, order, last_dflt, &last_resort, &last_idx,
  357. + &last_nhsel, key)) {
  358. if (res->fi)
  359. fib_info_put(res->fi);
  360. res->fi = fi;
  361. atomic_inc(&fi->fib_clntref);
  362. - fn_hash_last_dflt = order;
  363. + first_node->fn_last_dflt = order;
  364. goto out;
  365. }
  366. @@ -428,8 +489,11 @@ fn_hash_select_default(struct fib_table
  367. res->fi = last_resort;
  368. if (last_resort)
  369. atomic_inc(&last_resort->fib_clntref);
  370. + read_lock_bh(&fib_nhflags_lock);
  371. + last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
  372. + read_unlock_bh(&fib_nhflags_lock);
  373. + first_node->fn_last_dflt = last_idx;
  374. }
  375. - fn_hash_last_dflt = last_idx;
  376. out:
  377. read_unlock(&fib_hash_lock);
  378. }
  379. @@ -589,6 +653,7 @@ replace:
  380. memset(new_f, 0, sizeof(struct fib_node));
  381. + new_f->fn_last_dflt = -1;
  382. new_f->fn_key = key;
  383. #ifdef CONFIG_IP_ROUTE_TOS
  384. new_f->fn_tos = tos;
  385. Index: linux-2.4.35.4/net/ipv4/fib_rules.c
  386. ===================================================================
  387. --- linux-2.4.35.4.orig/net/ipv4/fib_rules.c
  388. +++ linux-2.4.35.4/net/ipv4/fib_rules.c
  389. @@ -307,6 +307,11 @@ static void fib_rules_attach(struct net_
  390. }
  391. }
  392. +int fib_result_table(struct fib_result *res)
  393. +{
  394. + return res->r->r_table;
  395. +}
  396. +
  397. int fib_lookup(const struct rt_key *key, struct fib_result *res)
  398. {
  399. int err;
  400. @@ -371,8 +376,10 @@ FRprintk("FAILURE\n");
  401. void fib_select_default(const struct rt_key *key, struct fib_result *res)
  402. {
  403. - if (res->r && res->r->r_action == RTN_UNICAST &&
  404. - FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
  405. + if (res->r &&
  406. + (res->r->r_action == RTN_UNICAST || res->r->r_action == RTN_NAT) &&
  407. + ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
  408. + FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)) {
  409. struct fib_table *tb;
  410. if ((tb = fib_get_table(res->r->r_table)) != NULL)
  411. tb->tb_select_default(tb, key, res);
  412. Index: linux-2.4.35.4/net/ipv4/fib_semantics.c
  413. ===================================================================
  414. --- linux-2.4.35.4.orig/net/ipv4/fib_semantics.c
  415. +++ linux-2.4.35.4/net/ipv4/fib_semantics.c
  416. @@ -48,6 +48,7 @@
  417. static struct fib_info *fib_info_list;
  418. static rwlock_t fib_info_lock = RW_LOCK_UNLOCKED;
  419. int fib_info_cnt;
  420. +rwlock_t fib_nhflags_lock = RW_LOCK_UNLOCKED;
  421. #define for_fib_info() { struct fib_info *fi; \
  422. for (fi = fib_info_list; fi; fi = fi->fib_next)
  423. @@ -150,7 +151,7 @@ static __inline__ int nh_comp(const stru
  424. #ifdef CONFIG_NET_CLS_ROUTE
  425. nh->nh_tclassid != onh->nh_tclassid ||
  426. #endif
  427. - ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
  428. + ((nh->nh_flags^onh->nh_flags)&~RTNH_F_BADSTATE))
  429. return -1;
  430. onh++;
  431. } endfor_nexthops(fi);
  432. @@ -166,7 +167,7 @@ static __inline__ struct fib_info * fib_
  433. nfi->fib_prefsrc == fi->fib_prefsrc &&
  434. nfi->fib_priority == fi->fib_priority &&
  435. memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
  436. - ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
  437. + ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_BADSTATE) == 0 &&
  438. (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
  439. return fi;
  440. } endfor_fib_info();
  441. @@ -365,8 +366,11 @@ static int fib_check_nh(const struct rtm
  442. return -EINVAL;
  443. if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
  444. return -ENODEV;
  445. - if (!(dev->flags&IFF_UP))
  446. - return -ENETDOWN;
  447. + if (!(dev->flags&IFF_UP)) {
  448. + if (fi->fib_protocol != RTPROT_STATIC)
  449. + return -ENETDOWN;
  450. + nh->nh_flags |= RTNH_F_DEAD;
  451. + }
  452. nh->nh_dev = dev;
  453. dev_hold(dev);
  454. nh->nh_scope = RT_SCOPE_LINK;
  455. @@ -380,23 +384,48 @@ static int fib_check_nh(const struct rtm
  456. /* It is not necessary, but requires a bit of thinking */
  457. if (key.scope < RT_SCOPE_LINK)
  458. key.scope = RT_SCOPE_LINK;
  459. - if ((err = fib_lookup(&key, &res)) != 0)
  460. - return err;
  461. - err = -EINVAL;
  462. - if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
  463. - goto out;
  464. - nh->nh_scope = res.scope;
  465. - nh->nh_oif = FIB_RES_OIF(res);
  466. - if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
  467. - goto out;
  468. - dev_hold(nh->nh_dev);
  469. - err = -ENETDOWN;
  470. - if (!(nh->nh_dev->flags & IFF_UP))
  471. - goto out;
  472. - err = 0;
  473. +
  474. + err = fib_lookup(&key, &res);
  475. + if (err) {
  476. + struct in_device *in_dev;
  477. +
  478. + if (err != -ENETUNREACH ||
  479. + fi->fib_protocol != RTPROT_STATIC)
  480. + return err;
  481. +
  482. + in_dev = inetdev_by_index(nh->nh_oif);
  483. + if (in_dev == NULL ||
  484. + in_dev->dev->flags & IFF_UP) {
  485. + if (in_dev)
  486. + in_dev_put(in_dev);
  487. + return err;
  488. + }
  489. + nh->nh_flags |= RTNH_F_DEAD;
  490. + nh->nh_scope = RT_SCOPE_LINK;
  491. + nh->nh_dev = in_dev->dev;
  492. + dev_hold(nh->nh_dev);
  493. + in_dev_put(in_dev);
  494. + } else {
  495. + err = -EINVAL;
  496. + if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
  497. + goto out;
  498. + nh->nh_scope = res.scope;
  499. + nh->nh_oif = FIB_RES_OIF(res);
  500. + if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
  501. + goto out;
  502. + dev_hold(nh->nh_dev);
  503. + if (!(nh->nh_dev->flags & IFF_UP)) {
  504. + if (fi->fib_protocol != RTPROT_STATIC) {
  505. + err = -ENETDOWN;
  506. + goto out;
  507. + }
  508. + nh->nh_flags |= RTNH_F_DEAD;
  509. + }
  510. + err = 0;
  511. out:
  512. - fib_res_put(&res);
  513. - return err;
  514. + fib_res_put(&res);
  515. + return err;
  516. + }
  517. } else {
  518. struct in_device *in_dev;
  519. @@ -407,8 +436,11 @@ out:
  520. if (in_dev == NULL)
  521. return -ENODEV;
  522. if (!(in_dev->dev->flags&IFF_UP)) {
  523. - in_dev_put(in_dev);
  524. - return -ENETDOWN;
  525. + if (fi->fib_protocol != RTPROT_STATIC) {
  526. + in_dev_put(in_dev);
  527. + return -ENETDOWN;
  528. + }
  529. + nh->nh_flags |= RTNH_F_DEAD;
  530. }
  531. nh->nh_dev = in_dev->dev;
  532. dev_hold(nh->nh_dev);
  533. @@ -606,8 +638,12 @@ fib_semantic_match(int type, struct fib_
  534. for_nexthops(fi) {
  535. if (nh->nh_flags&RTNH_F_DEAD)
  536. continue;
  537. - if (!key->oif || key->oif == nh->nh_oif)
  538. - break;
  539. + if (key->oif && key->oif != nh->nh_oif)
  540. + continue;
  541. + if (key->gw && key->gw != nh->nh_gw &&
  542. + nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
  543. + continue;
  544. + break;
  545. }
  546. #ifdef CONFIG_IP_ROUTE_MULTIPATH
  547. if (nhsel < fi->fib_nhs) {
  548. @@ -873,22 +909,35 @@ int fib_sync_down(u32 local, struct net_
  549. if (local && fi->fib_prefsrc == local) {
  550. fi->fib_flags |= RTNH_F_DEAD;
  551. ret++;
  552. - } else if (dev && fi->fib_nhs) {
  553. + } else if (fi->fib_nhs) {
  554. int dead = 0;
  555. change_nexthops(fi) {
  556. - if (nh->nh_flags&RTNH_F_DEAD)
  557. - dead++;
  558. - else if (nh->nh_dev == dev &&
  559. - nh->nh_scope != scope) {
  560. - nh->nh_flags |= RTNH_F_DEAD;
  561. + if (nh->nh_flags&RTNH_F_DEAD) {
  562. + if (fi->fib_protocol!=RTPROT_STATIC ||
  563. + nh->nh_dev == NULL ||
  564. + !__in_dev_get(nh->nh_dev) ||
  565. + nh->nh_dev->flags&IFF_UP)
  566. + dead++;
  567. + } else if ((nh->nh_dev == dev && dev &&
  568. + nh->nh_scope != scope) ||
  569. + (local == nh->nh_gw && local &&
  570. + nh->nh_oif)) {
  571. + write_lock_bh(&fib_nhflags_lock);
  572. #ifdef CONFIG_IP_ROUTE_MULTIPATH
  573. - spin_lock_bh(&fib_multipath_lock);
  574. + spin_lock(&fib_multipath_lock);
  575. + nh->nh_flags |= RTNH_F_DEAD;
  576. fi->fib_power -= nh->nh_power;
  577. nh->nh_power = 0;
  578. - spin_unlock_bh(&fib_multipath_lock);
  579. + spin_unlock(&fib_multipath_lock);
  580. +#else
  581. + nh->nh_flags |= RTNH_F_DEAD;
  582. #endif
  583. - dead++;
  584. + write_unlock_bh(&fib_nhflags_lock);
  585. + if (fi->fib_protocol!=RTPROT_STATIC ||
  586. + force ||
  587. + (dev && __in_dev_get(dev) == NULL))
  588. + dead++;
  589. }
  590. #ifdef CONFIG_IP_ROUTE_MULTIPATH
  591. if (force > 1 && nh->nh_dev == dev) {
  592. @@ -906,37 +955,55 @@ int fib_sync_down(u32 local, struct net_
  593. return ret;
  594. }
  595. -#ifdef CONFIG_IP_ROUTE_MULTIPATH
  596. -
  597. /*
  598. - Dead device goes up. We wake up dead nexthops.
  599. - It takes sense only on multipath routes.
  600. + Dead device goes up or new address is added. We wake up dead nexthops.
  601. */
  602. int fib_sync_up(struct net_device *dev)
  603. {
  604. - int ret = 0;
  605. + struct rt_key key;
  606. + struct fib_result res;
  607. + int ret, rep;
  608. +repeat:
  609. if (!(dev->flags&IFF_UP))
  610. return 0;
  611. + ret = 0;
  612. + rep = 0;
  613. for_fib_info() {
  614. int alive = 0;
  615. change_nexthops(fi) {
  616. - if (!(nh->nh_flags&RTNH_F_DEAD)) {
  617. - alive++;
  618. + if (!(nh->nh_flags&RTNH_F_DEAD))
  619. continue;
  620. - }
  621. if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
  622. continue;
  623. if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
  624. continue;
  625. + if (nh->nh_gw && fi->fib_protocol == RTPROT_STATIC) {
  626. + memset(&key, 0, sizeof(key));
  627. + key.dst = nh->nh_gw;
  628. + key.oif = nh->nh_oif;
  629. + key.scope = nh->nh_scope;
  630. + if (fib_lookup(&key, &res) != 0)
  631. + continue;
  632. + if (res.type != RTN_UNICAST &&
  633. + res.type != RTN_LOCAL) {
  634. + fib_res_put(&res);
  635. + continue;
  636. + }
  637. + nh->nh_scope = res.scope;
  638. + fib_res_put(&res);
  639. + rep = 1;
  640. + }
  641. alive++;
  642. +#ifdef CONFIG_IP_ROUTE_MULTIPATH
  643. spin_lock_bh(&fib_multipath_lock);
  644. nh->nh_power = 0;
  645. nh->nh_flags &= ~RTNH_F_DEAD;
  646. spin_unlock_bh(&fib_multipath_lock);
  647. +#endif
  648. } endfor_nexthops(fi)
  649. if (alive > 0) {
  650. @@ -944,9 +1011,13 @@ int fib_sync_up(struct net_device *dev)
  651. ret++;
  652. }
  653. } endfor_fib_info();
  654. + if (rep)
  655. + goto repeat;
  656. return ret;
  657. }
  658. +#ifdef CONFIG_IP_ROUTE_MULTIPATH
  659. +
  660. /*
  661. The algorithm is suboptimal, but it provides really
  662. fair weighted route distribution.
  663. @@ -955,24 +1026,45 @@ int fib_sync_up(struct net_device *dev)
  664. void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
  665. {
  666. struct fib_info *fi = res->fi;
  667. - int w;
  668. + int w, alive;
  669. spin_lock_bh(&fib_multipath_lock);
  670. + if (key->oif) {
  671. + int sel = -1;
  672. + w = -1;
  673. + change_nexthops(fi) {
  674. + if (key->oif != nh->nh_oif)
  675. + continue;
  676. + if (key->gw && key->gw != nh->nh_gw &&
  677. + nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
  678. + continue;
  679. + if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
  680. + if (nh->nh_power > w) {
  681. + w = nh->nh_power;
  682. + sel = nhsel;
  683. + }
  684. + }
  685. + } endfor_nexthops(fi);
  686. + if (sel >= 0) {
  687. + spin_unlock_bh(&fib_multipath_lock);
  688. + res->nh_sel = sel;
  689. + return;
  690. + }
  691. + goto last_resort;
  692. + }
  693. +
  694. +repeat:
  695. if (fi->fib_power <= 0) {
  696. int power = 0;
  697. change_nexthops(fi) {
  698. - if (!(nh->nh_flags&RTNH_F_DEAD)) {
  699. + if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
  700. power += nh->nh_weight;
  701. nh->nh_power = nh->nh_weight;
  702. }
  703. } endfor_nexthops(fi);
  704. fi->fib_power = power;
  705. - if (power <= 0) {
  706. - spin_unlock_bh(&fib_multipath_lock);
  707. - /* Race condition: route has just become dead. */
  708. - res->nh_sel = 0;
  709. - return;
  710. - }
  711. + if (power <= 0)
  712. + goto last_resort;
  713. }
  714. @@ -982,20 +1074,40 @@ void fib_select_multipath(const struct r
  715. w = jiffies % fi->fib_power;
  716. + alive = 0;
  717. change_nexthops(fi) {
  718. - if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
  719. + if (!(nh->nh_flags&RTNH_F_BADSTATE) && nh->nh_power) {
  720. if ((w -= nh->nh_power) <= 0) {
  721. nh->nh_power--;
  722. fi->fib_power--;
  723. - res->nh_sel = nhsel;
  724. spin_unlock_bh(&fib_multipath_lock);
  725. + res->nh_sel = nhsel;
  726. return;
  727. }
  728. + alive = 1;
  729. + }
  730. + } endfor_nexthops(fi);
  731. + if (alive) {
  732. + fi->fib_power = 0;
  733. + goto repeat;
  734. + }
  735. +
  736. +last_resort:
  737. +
  738. + for_nexthops(fi) {
  739. + if (!(nh->nh_flags&RTNH_F_DEAD)) {
  740. + if (key->oif && key->oif != nh->nh_oif)
  741. + continue;
  742. + if (key->gw && key->gw != nh->nh_gw &&
  743. + nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
  744. + continue;
  745. + spin_unlock_bh(&fib_multipath_lock);
  746. + res->nh_sel = nhsel;
  747. + return;
  748. }
  749. } endfor_nexthops(fi);
  750. /* Race condition: route has just become dead. */
  751. - res->nh_sel = 0;
  752. spin_unlock_bh(&fib_multipath_lock);
  753. }
  754. #endif
  755. Index: linux-2.4.35.4/net/ipv4/ip_nat_dumb.c
  756. ===================================================================
  757. --- linux-2.4.35.4.orig/net/ipv4/ip_nat_dumb.c
  758. +++ linux-2.4.35.4/net/ipv4/ip_nat_dumb.c
  759. @@ -124,6 +124,7 @@ ip_do_nat(struct sk_buff *skb)
  760. key.dst = ciph->saddr;
  761. key.iif = skb->dev->ifindex;
  762. key.oif = 0;
  763. + key.gw = 0;
  764. #ifdef CONFIG_IP_ROUTE_TOS
  765. key.tos = RT_TOS(ciph->tos);
  766. #endif
  767. Index: linux-2.4.35.4/net/ipv4/netfilter/ip_fw_compat_masq.c
  768. ===================================================================
  769. --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_fw_compat_masq.c
  770. +++ linux-2.4.35.4/net/ipv4/netfilter/ip_fw_compat_masq.c
  771. @@ -41,6 +41,10 @@ do_masquerade(struct sk_buff **pskb, con
  772. enum ip_conntrack_info ctinfo;
  773. struct ip_conntrack *ct;
  774. unsigned int ret;
  775. + struct rtable *rt, *skb_rt;
  776. + struct net_device *skb_dev;
  777. + __u32 saddr;
  778. + int new;
  779. /* Sorry, only ICMP, TCP and UDP. */
  780. if (iph->protocol != IPPROTO_ICMP
  781. @@ -64,22 +68,28 @@ do_masquerade(struct sk_buff **pskb, con
  782. }
  783. info = &ct->nat.info;
  784. + iph = (*pskb)->nh.iph;
  785. + saddr = iph->saddr;
  786. + new = 0;
  787. WRITE_LOCK(&ip_nat_lock);
  788. /* Setup the masquerade, if not already */
  789. if (!info->initialized) {
  790. u_int32_t newsrc;
  791. - struct rtable *rt;
  792. struct ip_nat_multi_range range;
  793. + skb_rt = (struct rtable *) (*pskb)->dst;
  794. + skb_dev = skb_rt->u.dst.dev;
  795. /* Pass 0 instead of saddr, since it's going to be changed
  796. anyway. */
  797. - if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) {
  798. + if (ip_route_output_lookup(&rt, iph->daddr, 0, RT_TOS(iph->tos),
  799. + skb_dev? skb_dev->ifindex : 0,
  800. + skb_dev? skb_rt->rt_gateway : 0) != 0) {
  801. + WRITE_UNLOCK(&ip_nat_lock);
  802. DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
  803. return NF_DROP;
  804. }
  805. - newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
  806. - RT_SCOPE_UNIVERSE);
  807. + newsrc = rt->rt_src;
  808. ip_rt_put(rt);
  809. range = ((struct ip_nat_multi_range)
  810. { 1,
  811. @@ -92,11 +102,31 @@ do_masquerade(struct sk_buff **pskb, con
  812. WRITE_UNLOCK(&ip_nat_lock);
  813. return ret;
  814. }
  815. + new = 1;
  816. } else
  817. DEBUGP("Masquerading already done on this conn.\n");
  818. WRITE_UNLOCK(&ip_nat_lock);
  819. - return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
  820. + ret = do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
  821. + if (ret != NF_ACCEPT || saddr == (*pskb)->nh.iph->saddr || new)
  822. + return ret;
  823. +
  824. + iph = (*pskb)->nh.iph;
  825. + if (ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), 0) != 0)
  826. + return NF_DROP;
  827. +
  828. + skb_rt = (struct rtable *) (*pskb)->dst;
  829. + skb_dev = skb_rt->u.dst.dev;
  830. + if (skb_dev != rt->u.dst.dev || rt->rt_gateway != skb_rt->rt_gateway) {
  831. + if (skb_dev != rt->u.dst.dev) {
  832. + /* TODO: check the new mtu and reply FRAG_NEEDED */
  833. + }
  834. + dst_release((*pskb)->dst);
  835. + (*pskb)->dst = &rt->u.dst;
  836. + } else {
  837. + ip_rt_put(rt);
  838. + }
  839. + return NF_ACCEPT;
  840. }
  841. void
  842. Index: linux-2.4.35.4/net/ipv4/netfilter/ip_nat_core.c
  843. ===================================================================
  844. --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_nat_core.c
  845. +++ linux-2.4.35.4/net/ipv4/netfilter/ip_nat_core.c
  846. @@ -994,6 +994,60 @@ icmp_reply_translation(struct sk_buff *s
  847. return NF_ACCEPT;
  848. }
  849. +unsigned int
  850. +ip_nat_route_input(unsigned int hooknum,
  851. + struct sk_buff **pskb,
  852. + const struct net_device *in,
  853. + const struct net_device *out,
  854. + int (*okfn)(struct sk_buff *))
  855. +{
  856. + struct sk_buff *skb = *pskb;
  857. + struct iphdr *iph;
  858. + struct ip_conntrack *ct;
  859. + enum ip_conntrack_info ctinfo;
  860. + struct ip_nat_info *info;
  861. + enum ip_conntrack_dir dir;
  862. + __u32 saddr;
  863. + int i;
  864. +
  865. + if (!(ct = ip_conntrack_get(skb, &ctinfo)))
  866. + return NF_ACCEPT;
  867. +
  868. + info = &ct->nat.info;
  869. + if (!info->initialized)
  870. + return NF_ACCEPT;
  871. +
  872. + if (skb->dst)
  873. + return NF_ACCEPT;
  874. +
  875. + if (skb->len < sizeof(struct iphdr))
  876. + return NF_ACCEPT;
  877. +
  878. + iph = skb->nh.iph;
  879. + saddr = iph->saddr;
  880. + hooknum = NF_IP_POST_ROUTING;
  881. + dir = CTINFO2DIR(ctinfo);
  882. +
  883. + READ_LOCK(&ip_nat_lock);
  884. + for (i = 0; i < info->num_manips; i++) {
  885. + if (info->manips[i].direction == dir
  886. + && info->manips[i].hooknum == hooknum
  887. + && info->manips[i].maniptype == IP_NAT_MANIP_SRC) {
  888. + saddr = info->manips[i].manip.ip;
  889. + }
  890. + }
  891. + READ_UNLOCK(&ip_nat_lock);
  892. +
  893. + if (saddr == iph->saddr)
  894. + return NF_ACCEPT;
  895. +
  896. + if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos,
  897. + skb->dev, saddr))
  898. + return NF_DROP;
  899. +
  900. + return NF_ACCEPT;
  901. +}
  902. +
  903. int __init ip_nat_init(void)
  904. {
  905. size_t i;
  906. Index: linux-2.4.35.4/net/ipv4/netfilter/ip_nat_standalone.c
  907. ===================================================================
  908. --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_nat_standalone.c
  909. +++ linux-2.4.35.4/net/ipv4/netfilter/ip_nat_standalone.c
  910. @@ -245,6 +245,9 @@ ip_nat_local_fn(unsigned int hooknum,
  911. /* Before packet filtering, change destination */
  912. static struct nf_hook_ops ip_nat_in_ops
  913. = { { NULL, NULL }, ip_nat_in, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST };
  914. +/* Before routing, route before mangling */
  915. +static struct nf_hook_ops ip_nat_inr_ops
  916. += { { NULL, NULL }, ip_nat_route_input, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_LAST-1 };
  917. /* After packet filtering, change source */
  918. static struct nf_hook_ops ip_nat_out_ops
  919. = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC};
  920. @@ -313,10 +316,15 @@ static int init_or_cleanup(int init)
  921. printk("ip_nat_init: can't register in hook.\n");
  922. goto cleanup_nat;
  923. }
  924. + ret = nf_register_hook(&ip_nat_inr_ops);
  925. + if (ret < 0) {
  926. + printk("ip_nat_init: can't register inr hook.\n");
  927. + goto cleanup_inops;
  928. + }
  929. ret = nf_register_hook(&ip_nat_out_ops);
  930. if (ret < 0) {
  931. printk("ip_nat_init: can't register out hook.\n");
  932. - goto cleanup_inops;
  933. + goto cleanup_inrops;
  934. }
  935. ret = nf_register_hook(&ip_nat_local_out_ops);
  936. if (ret < 0) {
  937. @@ -336,6 +344,8 @@ static int init_or_cleanup(int init)
  938. nf_unregister_hook(&ip_nat_local_out_ops);
  939. cleanup_outops:
  940. nf_unregister_hook(&ip_nat_out_ops);
  941. + cleanup_inrops:
  942. + nf_unregister_hook(&ip_nat_inr_ops);
  943. cleanup_inops:
  944. nf_unregister_hook(&ip_nat_in_ops);
  945. cleanup_nat:
  946. Index: linux-2.4.35.4/net/ipv4/netfilter/ipt_MASQUERADE.c
  947. ===================================================================
  948. --- linux-2.4.35.4.orig/net/ipv4/netfilter/ipt_MASQUERADE.c
  949. +++ linux-2.4.35.4/net/ipv4/netfilter/ipt_MASQUERADE.c
  950. @@ -87,7 +87,8 @@ masquerade_target(struct sk_buff **pskb,
  951. key.dst = (*pskb)->nh.iph->daddr;
  952. key.src = 0; /* Unknown: that's what we're trying to establish */
  953. key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN;
  954. - key.oif = 0;
  955. + key.oif = out->ifindex;
  956. + key.gw = ((struct rtable *) (*pskb)->dst)->rt_gateway;
  957. #ifdef CONFIG_IP_ROUTE_FWMARK
  958. key.fwmark = (*pskb)->nfmark;
  959. #endif
  960. @@ -98,13 +99,6 @@ masquerade_target(struct sk_buff **pskb,
  961. " No route: Rusty's brain broke!\n");
  962. return NF_DROP;
  963. }
  964. - if (rt->u.dst.dev != out) {
  965. - if (net_ratelimit())
  966. - printk("MASQUERADE:"
  967. - " Route sent us somewhere else.\n");
  968. - ip_rt_put(rt);
  969. - return NF_DROP;
  970. - }
  971. newsrc = rt->rt_src;
  972. DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc));
  973. Index: linux-2.4.35.4/net/ipv4/route.c
  974. ===================================================================
  975. --- linux-2.4.35.4.orig/net/ipv4/route.c
  976. +++ linux-2.4.35.4/net/ipv4/route.c
  977. @@ -919,6 +919,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
  978. /* Gateway is different ... */
  979. rt->rt_gateway = new_gw;
  980. + if (rt->key.gw) rt->key.gw = new_gw;
  981. /* Redirect received -> path was valid */
  982. dst_confirm(&rth->u.dst);
  983. @@ -1343,6 +1344,7 @@ static int ip_route_input_mc(struct sk_b
  984. rth->key.fwmark = skb->nfmark;
  985. #endif
  986. rth->key.src = saddr;
  987. + rth->key.lsrc = 0;
  988. rth->rt_src = saddr;
  989. #ifdef CONFIG_IP_ROUTE_NAT
  990. rth->rt_dst_map = daddr;
  991. @@ -1356,6 +1358,7 @@ static int ip_route_input_mc(struct sk_b
  992. rth->u.dst.dev = &loopback_dev;
  993. dev_hold(rth->u.dst.dev);
  994. rth->key.oif = 0;
  995. + rth->key.gw = 0;
  996. rth->rt_gateway = daddr;
  997. rth->rt_spec_dst= spec_dst;
  998. rth->rt_type = RTN_MULTICAST;
  999. @@ -1395,7 +1398,7 @@ e_inval:
  1000. */
  1001. int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
  1002. - u8 tos, struct net_device *dev)
  1003. + u8 tos, struct net_device *dev, u32 lsrc)
  1004. {
  1005. struct rt_key key;
  1006. struct fib_result res;
  1007. @@ -1415,16 +1418,17 @@ int ip_route_input_slow(struct sk_buff *
  1008. goto out;
  1009. key.dst = daddr;
  1010. - key.src = saddr;
  1011. + key.src = lsrc? : saddr;
  1012. key.tos = tos;
  1013. #ifdef CONFIG_IP_ROUTE_FWMARK
  1014. key.fwmark = skb->nfmark;
  1015. #endif
  1016. - key.iif = dev->ifindex;
  1017. + key.iif = lsrc? loopback_dev.ifindex : dev->ifindex;
  1018. key.oif = 0;
  1019. + key.gw = 0;
  1020. key.scope = RT_SCOPE_UNIVERSE;
  1021. - hash = rt_hash_code(daddr, saddr ^ (key.iif << 5), tos);
  1022. + hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos);
  1023. /* Check for the most weird martians, which can be not detected
  1024. by fib_lookup.
  1025. @@ -1445,6 +1449,12 @@ int ip_route_input_slow(struct sk_buff *
  1026. if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr))
  1027. goto martian_destination;
  1028. + if (lsrc) {
  1029. + if (MULTICAST(lsrc) || BADCLASS(lsrc) ||
  1030. + ZERONET(lsrc) || LOOPBACK(lsrc))
  1031. + goto e_inval;
  1032. + }
  1033. +
  1034. /*
  1035. * Now we are ready to route packet.
  1036. */
  1037. @@ -1454,6 +1464,10 @@ int ip_route_input_slow(struct sk_buff *
  1038. goto no_route;
  1039. }
  1040. free_res = 1;
  1041. + if (lsrc && res.type != RTN_UNICAST && res.type != RTN_NAT)
  1042. + goto e_inval;
  1043. + key.iif = dev->ifindex;
  1044. + key.src = saddr;
  1045. rt_cache_stat[smp_processor_id()].in_slow_tot++;
  1046. @@ -1464,7 +1478,7 @@ int ip_route_input_slow(struct sk_buff *
  1047. if (1) {
  1048. u32 src_map = saddr;
  1049. - if (res.r)
  1050. + if (res.r && !lsrc)
  1051. src_map = fib_rules_policy(saddr, &res, &flags);
  1052. if (res.type == RTN_NAT) {
  1053. @@ -1503,8 +1517,9 @@ int ip_route_input_slow(struct sk_buff *
  1054. if (res.type != RTN_UNICAST)
  1055. goto martian_destination;
  1056. + fib_select_default(&key, &res);
  1057. #ifdef CONFIG_IP_ROUTE_MULTIPATH
  1058. - if (res.fi->fib_nhs > 1 && key.oif == 0)
  1059. + if (res.fi->fib_nhs > 1)
  1060. fib_select_multipath(&key, &res);
  1061. #endif
  1062. out_dev = in_dev_get(FIB_RES_DEV(res));
  1063. @@ -1524,6 +1539,7 @@ int ip_route_input_slow(struct sk_buff *
  1064. flags |= RTCF_DIRECTSRC;
  1065. if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) &&
  1066. + !lsrc &&
  1067. (IN_DEV_SHARED_MEDIA(out_dev) ||
  1068. inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res))))
  1069. flags |= RTCF_DOREDIRECT;
  1070. @@ -1550,6 +1566,7 @@ int ip_route_input_slow(struct sk_buff *
  1071. #endif
  1072. rth->key.src = saddr;
  1073. rth->rt_src = saddr;
  1074. + rth->key.lsrc = lsrc;
  1075. rth->rt_gateway = daddr;
  1076. #ifdef CONFIG_IP_ROUTE_NAT
  1077. rth->rt_src_map = key.src;
  1078. @@ -1562,6 +1579,7 @@ int ip_route_input_slow(struct sk_buff *
  1079. rth->u.dst.dev = out_dev->dev;
  1080. dev_hold(rth->u.dst.dev);
  1081. rth->key.oif = 0;
  1082. + rth->key.gw = 0;
  1083. rth->rt_spec_dst= spec_dst;
  1084. rth->u.dst.input = ip_forward;
  1085. @@ -1572,7 +1590,8 @@ int ip_route_input_slow(struct sk_buff *
  1086. rth->rt_flags = flags;
  1087. #ifdef CONFIG_NET_FASTROUTE
  1088. - if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT))) {
  1089. + if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT)) &&
  1090. + !lsrc) {
  1091. struct net_device *odev = rth->u.dst.dev;
  1092. if (odev != dev &&
  1093. dev->accept_fastpath &&
  1094. @@ -1595,6 +1614,8 @@ out: return err;
  1095. brd_input:
  1096. if (skb->protocol != htons(ETH_P_IP))
  1097. goto e_inval;
  1098. + if (lsrc)
  1099. + goto e_inval;
  1100. if (ZERONET(saddr))
  1101. spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
  1102. @@ -1627,6 +1648,7 @@ local_input:
  1103. #endif
  1104. rth->key.src = saddr;
  1105. rth->rt_src = saddr;
  1106. + rth->key.lsrc = 0;
  1107. #ifdef CONFIG_IP_ROUTE_NAT
  1108. rth->rt_dst_map = key.dst;
  1109. rth->rt_src_map = key.src;
  1110. @@ -1639,6 +1661,7 @@ local_input:
  1111. rth->u.dst.dev = &loopback_dev;
  1112. dev_hold(rth->u.dst.dev);
  1113. rth->key.oif = 0;
  1114. + rth->key.gw = 0;
  1115. rth->rt_gateway = daddr;
  1116. rth->rt_spec_dst= spec_dst;
  1117. rth->u.dst.input= ip_local_deliver;
  1118. @@ -1704,8 +1727,9 @@ martian_source:
  1119. goto e_inval;
  1120. }
  1121. -int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
  1122. - u8 tos, struct net_device *dev)
  1123. +static inline int
  1124. +ip_route_input_cached(struct sk_buff *skb, u32 daddr, u32 saddr,
  1125. + u8 tos, struct net_device *dev, u32 lsrc)
  1126. {
  1127. struct rtable * rth;
  1128. unsigned hash;
  1129. @@ -1719,6 +1743,7 @@ int ip_route_input(struct sk_buff *skb,
  1130. if (rth->key.dst == daddr &&
  1131. rth->key.src == saddr &&
  1132. rth->key.iif == iif &&
  1133. + rth->key.lsrc == lsrc &&
  1134. rth->key.oif == 0 &&
  1135. #ifdef CONFIG_IP_ROUTE_FWMARK
  1136. rth->key.fwmark == skb->nfmark &&
  1137. @@ -1766,9 +1791,21 @@ int ip_route_input(struct sk_buff *skb,
  1138. read_unlock(&inetdev_lock);
  1139. return -EINVAL;
  1140. }
  1141. - return ip_route_input_slow(skb, daddr, saddr, tos, dev);
  1142. + return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc);
  1143. +}
  1144. +
  1145. +int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
  1146. + u8 tos, struct net_device *dev)
  1147. +{
  1148. + return ip_route_input_cached(skb, daddr, saddr, tos, dev, 0);
  1149. }
  1150. +int ip_route_input_lookup(struct sk_buff *skb, u32 daddr, u32 saddr,
  1151. + u8 tos, struct net_device *dev, u32 lsrc)
  1152. +{
  1153. + return ip_route_input_cached(skb, daddr, saddr, tos, dev, lsrc);
  1154. +}
  1155. +
  1156. /*
  1157. * Major route resolver routine.
  1158. */
  1159. @@ -1791,6 +1828,7 @@ int ip_route_output_slow(struct rtable *
  1160. key.tos = tos & IPTOS_RT_MASK;
  1161. key.iif = loopback_dev.ifindex;
  1162. key.oif = oldkey->oif;
  1163. + key.gw = oldkey->gw;
  1164. #ifdef CONFIG_IP_ROUTE_FWMARK
  1165. key.fwmark = oldkey->fwmark;
  1166. #endif
  1167. @@ -1880,6 +1918,7 @@ int ip_route_output_slow(struct rtable *
  1168. dev_out = &loopback_dev;
  1169. dev_hold(dev_out);
  1170. key.oif = loopback_dev.ifindex;
  1171. + key.gw = 0;
  1172. res.type = RTN_LOCAL;
  1173. flags |= RTCF_LOCAL;
  1174. goto make_route;
  1175. @@ -1887,7 +1926,7 @@ int ip_route_output_slow(struct rtable *
  1176. if (fib_lookup(&key, &res)) {
  1177. res.fi = NULL;
  1178. - if (oldkey->oif) {
  1179. + if (oldkey->oif && dev_out->flags&IFF_UP) {
  1180. /* Apparently, routing tables are wrong. Assume,
  1181. that the destination is on link.
  1182. @@ -1930,6 +1969,7 @@ int ip_route_output_slow(struct rtable *
  1183. dev_out = &loopback_dev;
  1184. dev_hold(dev_out);
  1185. key.oif = dev_out->ifindex;
  1186. + key.gw = 0;
  1187. if (res.fi)
  1188. fib_info_put(res.fi);
  1189. res.fi = NULL;
  1190. @@ -1937,13 +1977,12 @@ int ip_route_output_slow(struct rtable *
  1191. goto make_route;
  1192. }
  1193. + if (res.type == RTN_UNICAST)
  1194. + fib_select_default(&key, &res);
  1195. #ifdef CONFIG_IP_ROUTE_MULTIPATH
  1196. - if (res.fi->fib_nhs > 1 && key.oif == 0)
  1197. + if (res.fi->fib_nhs > 1)
  1198. fib_select_multipath(&key, &res);
  1199. - else
  1200. #endif
  1201. - if (!res.prefixlen && res.type == RTN_UNICAST && !key.oif)
  1202. - fib_select_default(&key, &res);
  1203. if (!key.src)
  1204. key.src = FIB_RES_PREFSRC(res);
  1205. @@ -2001,7 +2040,9 @@ make_route:
  1206. rth->key.tos = tos;
  1207. rth->key.src = oldkey->src;
  1208. rth->key.iif = 0;
  1209. + rth->key.lsrc = 0;
  1210. rth->key.oif = oldkey->oif;
  1211. + rth->key.gw = oldkey->gw;
  1212. #ifdef CONFIG_IP_ROUTE_FWMARK
  1213. rth->key.fwmark = oldkey->fwmark;
  1214. #endif
  1215. @@ -2080,6 +2121,7 @@ int ip_route_output_key(struct rtable **
  1216. rth->key.src == key->src &&
  1217. rth->key.iif == 0 &&
  1218. rth->key.oif == key->oif &&
  1219. + rth->key.gw == key->gw &&
  1220. #ifdef CONFIG_IP_ROUTE_FWMARK
  1221. rth->key.fwmark == key->fwmark &&
  1222. #endif
  1223. Index: linux-2.4.35.4/net/netsyms.c
  1224. ===================================================================
  1225. --- linux-2.4.35.4.orig/net/netsyms.c
  1226. +++ linux-2.4.35.4/net/netsyms.c
  1227. @@ -260,6 +260,7 @@ EXPORT_SYMBOL(inet_register_protosw);
  1228. EXPORT_SYMBOL(inet_unregister_protosw);
  1229. EXPORT_SYMBOL(ip_route_output_key);
  1230. EXPORT_SYMBOL(ip_route_input);
  1231. +EXPORT_SYMBOL(ip_route_input_lookup);
  1232. EXPORT_SYMBOL(icmp_send);
  1233. EXPORT_SYMBOL(icmp_statistics);
  1234. EXPORT_SYMBOL(icmp_err_convert);