Author: melifaro Date: Fri Mar 8 20:33:50 2013 New Revision: 248070 URL: http://svnweb.freebsd.org/changeset/base/248070
Log: Fix long-standing issue with interface routes being unprotected: Use RTM_PINNED flag to mark route as immutable. Forbid deleting immutable routes without special rtrequest1_fib() flag. Adding interface address with prefix already in route table is handled by atomically deleting old prefix and adding interface one. Discussed with: andre, eri MFC after: 3 weeks Modified: head/sys/net/if.c head/sys/net/route.c head/sys/net/route.h Modified: head/sys/net/if.c ============================================================================== --- head/sys/net/if.c Fri Mar 8 20:23:55 2013 (r248069) +++ head/sys/net/if.c Fri Mar 8 20:33:50 2013 (r248070) @@ -1357,7 +1357,8 @@ if_rtdel(struct radix_node *rn, void *ar return (0); err = rtrequest_fib(RTM_DELETE, rt_key(rt), rt->rt_gateway, - rt_mask(rt), rt->rt_flags|RTF_RNH_LOCKED, + rt_mask(rt), + rt->rt_flags|RTF_RNH_LOCKED|RTF_PINNED, (struct rtentry **) NULL, rt->rt_fibnum); if (err) { log(LOG_WARNING, "if_rtdel: error %d\n", err); Modified: head/sys/net/route.c ============================================================================== --- head/sys/net/route.c Fri Mar 8 20:23:55 2013 (r248069) +++ head/sys/net/route.c Fri Mar 8 20:33:50 2013 (r248070) @@ -1112,6 +1112,14 @@ rtrequest1_fib(int req, struct rt_addrin error = 0; } #endif + if ((flags & RTF_PINNED) == 0) { + /* Check if target route can be deleted */ + rt = (struct rtentry *)rnh->rnh_lookup(dst, + netmask, rnh); + if ((rt != NULL) && (rt->rt_flags & RTF_PINNED)) + senderr(EADDRINUSE); + } + /* * Remove the item from the tree and return it. * Complain if it is not there and do no more processing. @@ -1430,6 +1438,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int int didwork = 0; int a_failure = 0; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; + struct radix_node_head *rnh; if (flags & RTF_HOST) { dst = ifa->ifa_dstaddr; @@ -1488,7 +1497,6 @@ rtinit1(struct ifaddr *ifa, int cmd, int */ for ( fibnum = startfib; fibnum <= endfib; fibnum++) { if (cmd == RTM_DELETE) { - struct radix_node_head *rnh; struct radix_node *rn; /* * Look up an rtentry that is in the routing tree and @@ -1538,7 +1546,8 @@ rtinit1(struct ifaddr *ifa, int cmd, int */ bzero((caddr_t)&info, sizeof(info)); info.rti_ifa = ifa; - info.rti_flags = flags | (ifa->ifa_flags & ~IFA_RTSELF); + info.rti_flags = flags | + (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED; info.rti_info[RTAX_DST] = dst; /* * doing this for compatibility reasons @@ -1550,6 +1559,33 @@ rtinit1(struct ifaddr *ifa, int cmd, int info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; info.rti_info[RTAX_NETMASK] = netmask; error = rtrequest1_fib(cmd, &info, &rt, fibnum); + + if ((error == EEXIST) && (cmd == RTM_ADD)) { + /* + * Interface route addition failed. + * Atomically delete current prefix generating + * RTM_DELETE message, and retry adding + * interface prefix. + */ + rnh = rt_tables_get_rnh(fibnum, dst->sa_family); + RADIX_NODE_HEAD_LOCK(rnh); + + /* Delete old prefix */ + info.rti_ifa = NULL; + info.rti_flags = RTF_RNH_LOCKED; + + error = rtrequest1_fib(RTM_DELETE, &info, &rt, fibnum); + if (error == 0) { + info.rti_ifa = ifa; + info.rti_flags = flags | RTF_RNH_LOCKED | + (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED; + error = rtrequest1_fib(cmd, &info, &rt, fibnum); + } + + RADIX_NODE_HEAD_UNLOCK(rnh); + } + + if (error == 0 && rt != NULL) { /* * notify any listening routing agents of the change Modified: head/sys/net/route.h ============================================================================== --- head/sys/net/route.h Fri Mar 8 20:23:55 2013 (r248069) +++ head/sys/net/route.h Fri Mar 8 20:33:50 2013 (r248070) @@ -176,7 +176,7 @@ struct ortentry { /* 0x20000 unused, was RTF_WASCLONED */ #define RTF_PROTO3 0x40000 /* protocol specific routing flag */ /* 0x80000 unused */ -#define RTF_PINNED 0x100000 /* future use */ +#define RTF_PINNED 0x100000 /* route is immutable */ #define RTF_LOCAL 0x200000 /* route represents a local address */ #define RTF_BROADCAST 0x400000 /* route represents a bcast address */ #define RTF_MULTICAST 0x800000 /* route represents a mcast address */ _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"