The branch main has been updated by ae:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=c26d6bf9da013e839d9a696746ea1741569e619e

commit c26d6bf9da013e839d9a696746ea1741569e619e
Author:     Andrey V. Elsukov <[email protected]>
AuthorDate: 2025-10-17 07:53:35 +0000
Commit:     Andrey V. Elsukov <[email protected]>
CommitDate: 2025-10-17 08:22:36 +0000

    arp: fix adding proxy entries for P2P interfaces
    
    The old rtsock implementation used in-kernel workaround to do so.
    When route to specified destination address used P2P interface, the
    kernel did the search with ifa_ifwithnet() for most suitable network
    and then add proxy entry to this interface.
    
    Use similar approach with netlink implementation. We already have
    get_ether_addr() function that does almost the same thing as
    ifa_ifwithnet(). Use it when we find that destination route uses
    P2P interface and then try to guess suitable interface. This should
    fix the use of netlink-based arp(8) in mpd5.
    
    Rename get_ether_addr() to get_ifinfo(), since now it is used to find
    only ifindex in case when hwaddr is specified by user.
    Also make set_nl() and delete_nl() prototype similar to rtsock.
    And allow '-i' to be used with '-S', since we already allow the same
    for '-s'.
    
    PR:             290221
    Reported by:    eugen
    Reviewed by:    eugen
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D53113
---
 usr.sbin/arp/arp.c         | 32 ++++++++++++++++++++------------
 usr.sbin/arp/arp.h         |  9 ++++-----
 usr.sbin/arp/arp_netlink.c | 20 ++++++++++++++++----
 3 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c
index ee4236b5299b..055ef2ffe225 100644
--- a/usr.sbin/arp/arp.c
+++ b/usr.sbin/arp/arp.c
@@ -81,7 +81,6 @@ static int get(char *host);
 static int file(char *name);
 static struct rt_msghdr *rtmsg(int cmd,
     struct sockaddr_in *dst, struct sockaddr_dl *sdl);
-static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr);
 static int set_rtsock(struct sockaddr_in *dst, struct sockaddr_dl *sdl_m,
     char *host);
 
@@ -143,7 +142,8 @@ main(int argc, char *argv[])
        if (!func)
                func = F_GET;
        if (opts.rifname) {
-               if (func != F_GET && func != F_SET && !(func == F_DELETE && 
opts.aflag))
+               if (func != F_GET && func != F_SET && func != F_REPLACE &&
+                   !(func == F_DELETE && opts.aflag))
                        xo_errx(1, "-i not applicable to this operation");
                if ((opts.rifindex = if_nametoindex(opts.rifname)) == 0) {
                        if (errno == ENXIO)
@@ -273,7 +273,6 @@ getaddr(char *host)
        return (&reply);
 }
 
-int valid_type(int type);
 /*
  * Returns true if the type is a valid one for ARP.
  */
@@ -357,11 +356,14 @@ set(int argc, char **argv)
        }
        ea = (struct ether_addr *)LLADDR(&sdl_m);
        if ((opts.flags & RTF_ANNOUNCE) && !strcmp(eaddr, "auto")) {
-               if (!get_ether_addr(dst->sin_addr.s_addr, ea)) {
+               uint32_t ifindex;
+               if (!get_ifinfo(dst->sin_addr.s_addr, ea, &ifindex)) {
                        xo_warnx("no interface found for %s",
-                              inet_ntoa(dst->sin_addr));
+                           inet_ntoa(dst->sin_addr));
                        return (1);
                }
+               if (opts.rifindex == 0)
+                       opts.rifindex = ifindex;
                sdl_m.sdl_alen = ETHER_ADDR_LEN;
        } else {
                struct ether_addr *ea1 = ether_aton(eaddr);
@@ -375,7 +377,7 @@ set(int argc, char **argv)
                }
        }
 #ifndef WITHOUT_NETLINK
-       return (set_nl(opts.rifindex, dst, &sdl_m, host));
+       return (set_nl(dst, &sdl_m, host));
 #else
        return (set_rtsock(dst, &sdl_m, host));
 #endif
@@ -522,7 +524,7 @@ delete(char *host)
 #ifdef WITHOUT_NETLINK
        return (delete_rtsock(host));
 #else
-       return (delete_nl(0, host));
+       return (delete_nl(host));
 #endif
 }
 
@@ -819,11 +821,11 @@ doit:
 }
 
 /*
- * get_ether_addr - get the hardware address of an interface on the
- * same subnet as ipaddr.
+ * get_ifinfo - get the hardware address and if_index of an interface
+ * on the same subnet as ipaddr.
  */
-static int
-get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr)
+int
+get_ifinfo(in_addr_t ipaddr, struct ether_addr *hwaddr, uint32_t *pifindex)
 {
        struct ifaddrs *ifa, *ifd, *ifas = NULL;
        in_addr_t ina, mask;
@@ -862,7 +864,13 @@ get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr)
        }
        if (ifa == NULL)
                goto done;
-
+       if (pifindex != NULL)
+               *pifindex = if_nametoindex(ifa->ifa_name);
+       if (hwaddr == NULL) {
+               /* ether addr is not required */
+               retval = ETHER_ADDR_LEN;
+               goto done;
+       }
        /*
         * Now scan through again looking for a link-level address
         * for this interface.
diff --git a/usr.sbin/arp/arp.h b/usr.sbin/arp/arp.h
index 487863be43e7..512a238df425 100644
--- a/usr.sbin/arp/arp.h
+++ b/usr.sbin/arp/arp.h
@@ -2,8 +2,8 @@
 #define _USR_SBIN_ARP_ARP_H_
 
 int valid_type(int type);
+int get_ifinfo(in_addr_t ipaddr, struct ether_addr *hwaddr, uint32_t 
*pifindex);
 struct sockaddr_in *getaddr(char *host);
-int print_entries_nl(uint32_t ifindex, struct in_addr addr);
 
 struct arp_opts {
        bool aflag;
@@ -11,13 +11,12 @@ struct arp_opts {
        time_t expire_time;
        int flags;
        char *rifname;
-       unsigned int rifindex;
+       uint32_t rifindex;
 };
 extern struct arp_opts opts;
 
 int print_entries_nl(uint32_t ifindex, struct in_addr addr);
-int delete_nl(uint32_t ifindex, char *host);
-int set_nl(uint32_t ifindex, struct sockaddr_in *dst, struct sockaddr_dl *sdl,
-    char *host);
+int delete_nl(char *host);
+int set_nl(struct sockaddr_in *dst, struct sockaddr_dl *sdl, char *host);
 
 #endif
diff --git a/usr.sbin/arp/arp_netlink.c b/usr.sbin/arp/arp_netlink.c
index db1ef775dea2..34f21cf96f4f 100644
--- a/usr.sbin/arp/arp_netlink.c
+++ b/usr.sbin/arp/arp_netlink.c
@@ -79,13 +79,15 @@ get_link_info(struct snl_state *ss, uint32_t ifindex,
 
 
 static bool
-has_l2(struct snl_state *ss, uint32_t ifindex)
+has_l2(struct snl_state *ss, uint32_t ifindex, uint32_t *pflags)
 {
        struct snl_parsed_link_simple link = {};
 
+       *pflags = 0;
        if (!get_link_info(ss, ifindex, &link))
                return (false);
 
+       *pflags = link.ifi_flags;
        return (valid_type(link.ifi_type) != 0);
 }
 
@@ -104,6 +106,7 @@ static int
 guess_ifindex(struct snl_state *ss, uint32_t fibnum, struct in_addr addr)
 {
        struct snl_writer nw;
+       uint32_t ifindex, ifflags;
 
        snl_init_writer(ss, &nw);
 
@@ -133,9 +136,16 @@ guess_ifindex(struct snl_state *ss, uint32_t fibnum, 
struct in_addr addr)
                return (0);
 
        /* Check if the interface is of supported type */
-       if (has_l2(ss, r.rta_oif))
+       if (has_l2(ss, r.rta_oif, &ifflags))
                return (r.rta_oif);
 
+       /* Check if we are doing proxy arp for P2P interface */
+       if (ifflags & IFF_POINTOPOINT) {
+               /* Guess interface by dst prefix */
+               if (get_ifinfo(addr.s_addr, NULL, &ifindex))
+                       return (ifindex);
+       }
+
        /* Check the case when we matched the loopback route for P2P */
        snl_init_writer(ss, &nw);
        hdr = snl_create_msg_request(&nw, RTM_GETNEXTHOP);
@@ -326,11 +336,12 @@ print_entries_nl(uint32_t ifindex, struct in_addr addr)
 }
 
 int
-delete_nl(uint32_t ifindex, char *host)
+delete_nl(char *host)
 {
        struct snl_state ss = {};
        struct snl_writer nw;
        struct sockaddr_in *dst;
+       uint32_t ifindex = opts.rifindex;
 
        dst = getaddr(host);
        if (dst == NULL)
@@ -375,10 +386,11 @@ delete_nl(uint32_t ifindex, char *host)
 }
 
 int
-set_nl(uint32_t ifindex, struct sockaddr_in *dst, struct sockaddr_dl *sdl, 
char *host)
+set_nl(struct sockaddr_in *dst, struct sockaddr_dl *sdl, char *host)
 {
        struct snl_state ss = {};
        struct snl_writer nw;
+       uint32_t ifindex = opts.rifindex;
 
        nl_init_socket(&ss);
 

Reply via email to