# Problem statemen
Currently for the route addition requests with link-level gateway, source ifa selection (//rt_ifa//) is really hackish. The route goes through the entire insertion process with invalid ifa and got it changed immediately after insertion. This leads to complications in the various parts of routing stack.
Let's trace addition of the loopback interfaces route:
```
ifa_add_loopback_route() # is a wrapper for
ifa_maintain_loopback_route() # fills in _info_ structure with interface set to loopback but not filling in ifa.
rtequest1_fib() # validates and fills in remaining data, determes ifa by calling
rt_getifa_fib() # which uses gw & interface to call
ifaof_ifpforaddr() # which returns the link-level ifa matching link-level gw (AF_LINK "base" ifa for lo0)
```
Then, the route gets inserted into the routing table with invalid //rt_ifa//, we drop RIB_WLOCK and call ifa routing hook.
This hook is
```
link_rtrequest() # which again calls
ifaof_ifpforaddr() # this time with the `dst` as the socket, changes ifa to be the "proper" one and calls that rta handler.
```
This behaviour complicates routing code:
* at the moment of insertion ifa pointer is plain wrong
* ifa selection is way more complex
# Proposed solution
First, setup ifa explicitly for the loopback routes (always loopback IPv4/IPv6 address). This is effectively what we do now for both IPv4/IPv6 (see below).
Note: for IPv6 route IFA plays less important role as it uses its own SAS process, which selects the proper address by its own.
Second, move the logic from the link_rtrequest() to the rt_ifa_ifp(). High-level description: if the gateway is set, use gateway, otherwise use dst to guess ifa. However, still retain existing behaviour to ensure we still have _some_ ifa.
For example, it can be helpful if one adds directly-reachable interface prefix to an interface without any IP address.
# Testing
Combination of 'route -n monitor' output for the 'route -n get ....' are shown below as stock route get / netstat -rn does not show ifa.
## Before
m@devel0 route -n get -6 2a01:4f8:13a:70c:ffff::6
sockaddrs: <DST,GATEWAY,IFP,**IFA**>
2a01:4f8:13a:70c:ffff::6 link#1 lo0 **::1**
m@devel0 route -n get -6 fe80::5054:ff:fe42:fef%vtnet0
sockaddrs: <DST,GATEWAY,IFP,**IFA**>
fe80::5054:ff:fe42:fef%vtnet0 link#1 lo0 **::1**
14:48 [2] m@devel0 route -n get -6 ::1
sockaddrs: <DST,GATEWAY,IFP,**IFA**>
::1 link#2 lo0 **::1**
19:15 [1] m@devel2 route -n get -6 fe80::1%lo0
sockaddrs: <DST,GATEWAY,IFP,**IFA**>
fe80::1%lo0 link#2 lo0 **fe80::1%lo0**
## After
route -n get 10.0.0.157
sockaddrs: <DST,GATEWAY,IFP,**IFA**>
10.0.0.157 link#1 lo0 **127.0.0.1**
route -n get -6 ::ffff:0.0.0.0
sockaddrs: <DST,GATEWAY,NETMASK,IFP,**IFA**>
::ffff:0.0.0.0 ::1 ffff:ffff:ffff:ffff:ffff:ffff:: lo0 **::1**
route -n get -6 2a01:4f8:13a:70c:ffff::6
sockaddrs: <DST,GATEWAY,IFP,**IFA**>
2a01:4f8:13a:70c:ffff::6 link#1 lo0 **::1**
route -n get -6 fe80::5054:ff:fe42:fef%vtnet0
sockaddrs: <DST,GATEWAY,IFP,**IFA**>
fe80::5054:ff:fe42:fef%vtnet0 link#1 lo0 **::1**
route -n get -6 fe80::1%lo0
sockaddrs: <DST,GATEWAY,IFP,**IFA**>
fe80::1%lo0 link#2 lo0 **fe80::1%lo0**