On Tue, Mar 17, 2015 at 05:35:21PM +0100, Martin Pieuchot wrote: > On 12/02/15(Thu) 12:35, Martin Pieuchot wrote: > > On 10/02/15(Tue) 03:04, Claudio Jeker wrote: > > > There is no need to not allow the same network to be configured more then > > > once. Instead just rely on the multipath and priority handling of the > > > routing table to select the right route. > > > Additionally this removes cloned routes (arp/npd cache) when the interface > > > goes down or when the any of the multipath cloning route is changed. > > > > > > With this it is possible to run 2 dhclients on wired and wireless with a > > > bridged network. Active TCP sessions still fail when the cable is > > > unplugged. To fix this more is needed. > > > > > > This changes a fundamental part of the network stack and therefor broad > > > testing is needed to find all the hidden dragons. > > > > Here's version of the diff rebased on top of the recent changes. > > I think it's the time to get this in, then as a second step put the > dhclient(8) bits. > > Claudio you have my ok.
It is broken for IPv6 and I could not find the proper fix yet. I think I now why it goes wrong but the nd6 code is a nightmare. I will send out a new diff once I have IPv6 fixed. > > Index: net/if_var.h > > =================================================================== > > RCS file: /cvs/src/sys/net/if_var.h,v > > retrieving revision 1.20 > > diff -u -p -r1.20 if_var.h > > --- net/if_var.h 9 Feb 2015 03:09:57 -0000 1.20 > > +++ net/if_var.h 12 Feb 2015 11:08:40 -0000 > > @@ -392,6 +392,7 @@ do { > > \ > > /* default interface priorities */ > > #define IF_WIRED_DEFAULT_PRIORITY 0 > > #define IF_WIRELESS_DEFAULT_PRIORITY 4 > > +#define IF_CARP_DEFAULT_PRIORITY 15 > > > > extern struct ifnet_head ifnet; > > extern struct ifnet *lo0ifp; > > Index: net/route.c > > =================================================================== > > RCS file: /cvs/src/sys/net/route.c,v > > retrieving revision 1.206 > > diff -u -p -r1.206 route.c > > --- net/route.c 11 Feb 2015 23:34:43 -0000 1.206 > > +++ net/route.c 12 Feb 2015 11:08:40 -0000 > > @@ -554,6 +554,16 @@ rtdeletemsg(struct rtentry *rt, u_int ta > > return (error); > > } > > > > +static inline int > > +rtequal(struct rtentry *a, struct rtentry *b) > > +{ > > + if (memcmp(rt_key(a), rt_key(b), rt_key(a)->sa_len) == 0 && > > + memcmp(rt_mask(a), rt_mask(b), rt_mask(a)->sa_len) == 0) > > + return 1; > > + else > > + return 0; > > +} > > + > > int > > rtflushclone1(struct radix_node *rn, void *arg, u_int id) > > { > > @@ -561,7 +571,8 @@ rtflushclone1(struct radix_node *rn, voi > > > > rt = (struct rtentry *)rn; > > parent = (struct rtentry *)arg; > > - if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent) > > + if ((rt->rt_flags & RTF_CLONED) != 0 && (rt->rt_parent == parent || > > + rtequal(rt->rt_parent, parent))) > > rtdeletemsg(rt, id); > > return 0; > > } > > @@ -1106,16 +1117,20 @@ rt_ifa_add(struct ifaddr *ifa, int flags > > { > > struct rtentry *rt, *nrt = NULL; > > struct sockaddr_rtlabel sa_rl; > > + struct sockaddr_dl sa_dl = { sizeof(sa_dl), AF_LINK }; > > struct rt_addrinfo info; > > u_short rtableid = ifa->ifa_ifp->if_rdomain; > > - u_int8_t prio = RTP_CONNECTED; > > + u_int8_t prio = ifa->ifa_ifp->if_priority + RTP_STATIC; > > int error; > > > > + sa_dl.sdl_type = ifa->ifa_ifp->if_type; > > + sa_dl.sdl_index = ifa->ifa_ifp->if_index; > > + > > memset(&info, 0, sizeof(info)); > > info.rti_ifa = ifa; > > - info.rti_flags = flags; > > + info.rti_flags = flags | RTF_MPATH; > > info.rti_info[RTAX_DST] = dst; > > - info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; > > + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&sa_dl; > > info.rti_info[RTAX_LABEL] = > > rtlabel_id2sa(ifa->ifa_ifp->if_rtlabelid, &sa_rl); > > > > @@ -1161,8 +1176,9 @@ rt_ifa_del(struct ifaddr *ifa, int flags > > struct sockaddr *deldst; > > struct rt_addrinfo info; > > struct sockaddr_rtlabel sa_rl; > > + struct sockaddr_dl sa_dl = { sizeof(sa_dl), AF_LINK }; > > u_short rtableid = ifa->ifa_ifp->if_rdomain; > > - u_int8_t prio = RTP_CONNECTED; > > + u_int8_t prio = ifa->ifa_ifp->if_priority + RTP_STATIC; > > int error; > > > > if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { > > @@ -1187,10 +1203,14 @@ rt_ifa_del(struct ifaddr *ifa, int flags > > } > > } > > > > + sa_dl.sdl_type = ifa->ifa_ifp->if_type; > > + sa_dl.sdl_index = ifa->ifa_ifp->if_index; > > + > > memset(&info, 0, sizeof(info)); > > info.rti_ifa = ifa; > > info.rti_flags = flags; > > info.rti_info[RTAX_DST] = dst; > > + info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&sa_dl; > > info.rti_info[RTAX_LABEL] = > > rtlabel_id2sa(ifa->ifa_ifp->if_rtlabelid, &sa_rl); > > > > @@ -1692,6 +1715,15 @@ rt_if_linkstate_change(struct radix_node > > } > > } else { > > if (rt->rt_flags & RTF_UP) { > > + /* > > + * Remove cloned routes (mainly arp) to > > + * down interfaces so we have a chance to > > + * clone a new route from a better source. > > + */ > > + if (rt->rt_flags & RTF_CLONED) { > > + rtdeletemsg(rt, id); > > + return (0); > > + } > > /* take route down */ > > rt->rt_flags &= ~RTF_UP; > > rn_mpath_reprio(rn, rt->rt_priority | RTP_DOWN); > > Index: netinet/if_ether.c > > =================================================================== > > RCS file: /cvs/src/sys/netinet/if_ether.c,v > > retrieving revision 1.146 > > diff -u -p -r1.146 if_ether.c > > --- netinet/if_ether.c 11 Feb 2015 23:34:43 -0000 1.146 > > +++ netinet/if_ether.c 12 Feb 2015 11:10:11 -0000 > > @@ -111,8 +111,6 @@ void db_print_llinfo(caddr_t); > > int db_show_radix_node(struct radix_node *, void *, u_int); > > #endif > > > > -static const struct sockaddr_dl null_sdl = { sizeof(null_sdl), AF_LINK }; > > - > > /* > > * Timeout routine. Age arp_tab entries periodically. > > */ > > @@ -181,14 +179,6 @@ arp_rtrequest(int req, struct rtentry *r > > if (rt->rt_flags & RTF_CLONING || > > ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !la)) { > > /* > > - * Case 1: This route should come from a route to iface. > > - */ > > - rt_setgate(rt, (struct sockaddr *)&null_sdl, > > - ifp->if_rdomain); > > - gate = rt->rt_gateway; > > - SDL(gate)->sdl_type = ifp->if_type; > > - SDL(gate)->sdl_index = ifp->if_index; > > - /* > > * Give this route an expiration time, even though > > * it's a "permanent" route, so that routes cloned > > * from it do not need their expiration time set. > > @@ -251,10 +241,6 @@ arp_rtrequest(int req, struct rtentry *r > > } > > if (ifa) { > > rt->rt_expire = 0; > > - SDL(gate)->sdl_alen = ETHER_ADDR_LEN; > > - memcpy(LLADDR(SDL(gate)), > > - ((struct arpcom *)ifp)->ac_enaddr, ETHER_ADDR_LEN); > > - > > /* > > * XXX Since lo0 is in the default rdomain we > > * should not (ab)use it for any route related > > Index: netinet/in.c > > =================================================================== > > RCS file: /cvs/src/sys/netinet/in.c,v > > retrieving revision 1.115 > > diff -u -p -r1.115 in.c > > --- netinet/in.c 12 Jan 2015 13:51:45 -0000 1.115 > > +++ netinet/in.c 12 Feb 2015 11:08:40 -0000 > > @@ -93,8 +93,6 @@ int in_lifaddr_ioctl(struct socket *, u_ > > struct ifnet *); > > > > void in_purgeaddr(struct ifaddr *); > > -int in_addprefix(struct in_ifaddr *); > > -int in_scrubprefix(struct in_ifaddr *); > > int in_addhost(struct in_ifaddr *, struct sockaddr_in *); > > int in_scrubhost(struct in_ifaddr *, struct sockaddr_in *); > > int in_insert_prefix(struct in_ifaddr *); > > @@ -590,7 +588,8 @@ in_ifscrub(struct ifnet *ifp, struct in_ > > if (ISSET(ifp->if_flags, IFF_POINTOPOINT)) > > in_scrubhost(ia, &ia->ia_dstaddr); > > else if (!ISSET(ifp->if_flags, IFF_LOOPBACK)) > > - in_scrubprefix(ia); > > + if (ia->ia_flags & IFA_ROUTE) > > + in_remove_prefix(ia); > > } > > > > /* > > @@ -669,7 +668,7 @@ in_ifinit(struct ifnet *ifp, struct in_i > > goto out; > > error = in_addhost(ia, &ia->ia_dstaddr); > > } else if (!ISSET(ifp->if_flags, IFF_LOOPBACK)) { > > - error = in_addprefix(ia); > > + error = in_insert_prefix(ia); > > } > > > > /* > > @@ -759,125 +758,6 @@ in_remove_prefix(struct in_ifaddr *ia) > > ifa->ifa_broadaddr); > > > > ia->ia_flags &= ~IFA_ROUTE; > > -} > > - > > -/* > > - * add a route to prefix ("connected route" in cisco terminology). > > - * does nothing if there's some interface address with the same prefix > > already. > > - */ > > -int > > -in_addprefix(struct in_ifaddr *ia0) > > -{ > > - struct ifnet *ifp; > > - struct ifaddr *ifa; > > - struct in_ifaddr *ia; > > - struct in_addr prefix, mask, p, m; > > - > > - prefix = ia0->ia_addr.sin_addr; > > - mask = ia0->ia_sockmask.sin_addr; > > - prefix.s_addr &= mask.s_addr; > > - > > - TAILQ_FOREACH(ifp, &ifnet, if_list) { > > - if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) > > - continue; > > - > > - if (ifp->if_rdomain != ia0->ia_ifp->if_rdomain) > > - continue; > > - > > - TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { > > - if (ifa->ifa_addr->sa_family != AF_INET) > > - continue; > > - > > - ia = ifatoia(ifa); > > - > > - if ((ia->ia_flags & IFA_ROUTE) == 0) > > - continue; > > - > > - p = ia->ia_addr.sin_addr; > > - m = ia->ia_sockmask.sin_addr; > > - p.s_addr &= m.s_addr; > > - > > - if (prefix.s_addr != p.s_addr || > > - mask.s_addr != m.s_addr) > > - continue; > > - > > -#if NCARP > 0 > > - /* move to a real interface instead of carp interface */ > > - if (ia->ia_ifp->if_type == IFT_CARP && > > - ia0->ia_ifp->if_type != IFT_CARP) { > > - in_remove_prefix(ia); > > - break; > > - } > > -#endif > > - /* > > - * If we got a matching prefix route inserted by other > > - * interface address, we don't need to bother > > - */ > > - return (0); > > - } > > - } > > - > > - /* > > - * noone seem to have prefix route. insert it. > > - */ > > - return in_insert_prefix(ia0); > > -} > > - > > -/* > > - * remove a route to prefix ("connected route" in cisco terminology). > > - * re-installs the route by using another interface address, if there's one > > - * with the same prefix (otherwise we lose the route mistakenly). > > - */ > > -int > > -in_scrubprefix(struct in_ifaddr *ia0) > > -{ > > - struct ifnet *ifp; > > - struct ifaddr *ifa; > > - struct in_ifaddr *ia; > > - struct in_addr prefix, mask, p, m; > > - > > - if ((ia0->ia_flags & IFA_ROUTE) == 0) > > - return 0; > > - > > - prefix = ia0->ia_addr.sin_addr; > > - mask = ia0->ia_sockmask.sin_addr; > > - prefix.s_addr &= mask.s_addr; > > - > > - TAILQ_FOREACH(ifp, &ifnet, if_list) { > > - if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) > > - continue; > > - > > - if (ifp->if_rdomain != ia0->ia_ifp->if_rdomain) > > - continue; > > - > > - TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { > > - if (ifa->ifa_addr->sa_family != AF_INET) > > - continue; > > - > > - ia = ifatoia(ifa); > > - > > - if ((ia->ia_flags & IFA_ROUTE) != 0) > > - continue; > > - > > - p = ia->ia_addr.sin_addr; > > - m = ia->ia_sockmask.sin_addr; > > - p.s_addr &= m.s_addr; > > - > > - if (prefix.s_addr != p.s_addr || > > - mask.s_addr != m.s_addr) > > - continue; > > - > > - /* Move IFA_ROUTE to the matching prefix route. */ > > - in_remove_prefix(ia0); > > - return (in_insert_prefix(ia)); > > - } > > - } > > - > > - /* > > - * noone seem to have prefix route. remove it. > > - */ > > - in_remove_prefix(ia0); > > - return 0; > > } > > > > /* > > Index: netinet/ip_carp.c > > =================================================================== > > RCS file: /cvs/src/sys/netinet/ip_carp.c,v > > retrieving revision 1.246 > > diff -u -p -r1.246 ip_carp.c > > --- netinet/ip_carp.c 11 Feb 2015 04:29:29 -0000 1.246 > > +++ netinet/ip_carp.c 12 Feb 2015 11:15:40 -0000 > > @@ -751,6 +751,7 @@ carp_clone_create(ifc, unit) > > ifp->if_addrlen = ETHER_ADDR_LEN; > > ifp->if_hdrlen = ETHER_HDR_LEN; > > ifp->if_mtu = ETHERMTU; > > + ifp->if_priority = IF_CARP_DEFAULT_PRIORITY; > > IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); > > IFQ_SET_READY(&ifp->if_snd); > > if_attach(ifp); > > Index: netinet6/nd6.c > > =================================================================== > > RCS file: /cvs/src/sys/netinet6/nd6.c,v > > retrieving revision 1.131 > > diff -u -p -r1.131 nd6.c > > --- netinet6/nd6.c 11 Feb 2015 23:34:43 -0000 1.131 > > +++ netinet6/nd6.c 12 Feb 2015 11:10:40 -0000 > > @@ -957,7 +957,6 @@ nd6_rtrequest(int req, struct rtentry *r > > { > > struct sockaddr *gate = rt->rt_gateway; > > struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; > > - static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; > > struct ifnet *ifp = rt->rt_ifp; > > struct ifaddr *ifa; > > struct nd_defrouter *dr; > > @@ -1016,17 +1015,6 @@ nd6_rtrequest(int req, struct rtentry *r > > */ > > if ((rt->rt_flags & RTF_CLONING) || > > ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !ln)) { > > - /* > > - * Case 1: This route should come from a route to > > - * interface (RTF_CLONING case) or the route should be > > - * treated as on-link but is currently not > > - * (RTF_LLINFO && !ln case). > > - */ > > - rt_setgate(rt, (struct sockaddr *)&null_sdl, > > - ifp->if_rdomain); > > - gate = rt->rt_gateway; > > - SDL(gate)->sdl_type = ifp->if_type; > > - SDL(gate)->sdl_index = ifp->if_index; > > if (ln) > > nd6_llinfo_settimer(ln, 0); > > if ((rt->rt_flags & RTF_CLONING) != 0) > > @@ -1062,7 +1050,7 @@ nd6_rtrequest(int req, struct rtentry *r > > /* FALLTHROUGH */ > > case RTM_RESOLVE: > > if (gate->sa_family != AF_LINK || > > - gate->sa_len < sizeof(null_sdl)) { > > + gate->sa_len < sizeof(struct sockaddr_dl)) { > > log(LOG_DEBUG, "%s: bad gateway value: %s\n", > > __func__, ifp->if_xname); > > break; > > @@ -1144,14 +1132,9 @@ nd6_rtrequest(int req, struct rtentry *r > > ifa = &in6ifa_ifpwithaddr(ifp, > > &satosin6(rt_key(rt))->sin6_addr)->ia_ifa; > > if (ifa) { > > - caddr_t macp = nd6_ifptomac(ifp); > > nd6_llinfo_settimer(ln, -1); > > ln->ln_state = ND6_LLINFO_REACHABLE; > > ln->ln_byhint = 0; > > - if (macp) { > > - memcpy(LLADDR(SDL(gate)), macp, > > ifp->if_addrlen); > > - SDL(gate)->sdl_alen = ifp->if_addrlen; > > - } > > > > /* > > * XXX Since lo0 is in the default rdomain we > > > -- :wq Claudio