git: 7eee0eaf1602 - main - netlink: automatically generate broadcast for IPv4 ifa if not set.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 20 May 2023 10:43:04 UTC
The branch main has been updated by melifaro:
URL: https://cgit.FreeBSD.org/src/commit/?id=7eee0eaf1602765bdf20c8e56884069085812c27
commit 7eee0eaf1602765bdf20c8e56884069085812c27
Author: Alexander V. Chernikov <melifaro@FreeBSD.org>
AuthorDate: 2023-05-20 10:42:08 +0000
Commit: Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2023-05-20 10:42:08 +0000
netlink: automatically generate broadcast for IPv4 ifa if not set.
MFC after: 2 weeks
---
sys/netlink/route/iface.c | 34 +++++++++++++++++++++++++++-------
tests/sys/netlink/test_rtnl_ifaddr.py | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 7 deletions(-)
diff --git a/sys/netlink/route/iface.c b/sys/netlink/route/iface.c
index 976b485b3f56..33a5dbfec3a3 100644
--- a/sys/netlink/route/iface.c
+++ b/sys/netlink/route/iface.c
@@ -1096,13 +1096,14 @@ static int
handle_newaddr_inet(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs,
struct ifnet *ifp, struct nlpcb *nlp, struct nl_pstate *npt)
{
- if (attrs->ifa_prefixlen > 32) {
+ int plen = attrs->ifa_prefixlen;
+ int if_flags = if_getflags(ifp);
+
+ if (plen > 32) {
nlmsg_report_err_msg(npt, "invalid ifa_prefixlen");
return (EINVAL);
};
- int if_flags = if_getflags(ifp);
-
if (if_flags & IFF_POINTOPOINT) {
if (attrs->ifa_addr == NULL || attrs->ifa_dst == NULL) {
nlmsg_report_err_msg(npt, "Empty IFA_LOCAL/IFA_ADDRESS");
@@ -1115,13 +1116,32 @@ handle_newaddr_inet(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs,
}
attrs->ifa_dst = attrs->ifa_broadcast;
- if (attrs->ifa_dst == NULL && !(if_flags & IFF_LOOPBACK)) {
- nlmsg_report_err_msg(npt, "empty IFA_BROADCAST for BRD interface");
- return (EINVAL);
+ /* Generate broadcast address if not set */
+ if ((if_flags & IFF_BROADCAST) && attrs->ifa_dst == NULL) {
+ uint32_t s_baddr;
+ struct sockaddr_in *sin_brd;
+
+ if (plen == 31)
+ s_baddr = INADDR_BROADCAST; /* RFC 3021 */
+ else {
+ struct sockaddr_in *addr;
+ uint32_t s_mask;
+
+ addr = (struct sockaddr_in *)attrs->ifa_addr;
+ s_mask = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0);
+ s_baddr = addr->sin_addr.s_addr | ~s_mask;
+ }
+
+ sin_brd = (struct sockaddr_in *)npt_alloc(npt, sizeof(*sin_brd));
+ if (sin_brd == NULL)
+ return (ENOMEM);
+ sin_brd->sin_family = AF_INET;
+ sin_brd->sin_len = sizeof(*sin_brd);
+ sin_brd->sin_addr.s_addr = s_baddr;
+ attrs->ifa_dst = (struct sockaddr *)sin_brd;
}
}
- int plen = attrs->ifa_prefixlen;
struct sockaddr_in mask = {
.sin_len = sizeof(struct sockaddr_in),
.sin_family = AF_INET,
diff --git a/tests/sys/netlink/test_rtnl_ifaddr.py b/tests/sys/netlink/test_rtnl_ifaddr.py
index 11c08b32674a..c7d6d86e781b 100644
--- a/tests/sys/netlink/test_rtnl_ifaddr.py
+++ b/tests/sys/netlink/test_rtnl_ifaddr.py
@@ -254,6 +254,41 @@ class TestRtNlIfaddrOpsBroadcast(RtnlIfaOps):
assert rx_msg.get_nla(IfaAttrType.IFA_LOCAL).addr == str(ifa.ip)
assert rx_msg.get_nla(IfaAttrType.IFA_BROADCAST).addr == str(ifa_brd)
+ @pytest.mark.parametrize(
+ "brd",
+ [
+ pytest.param((32, True, "192.0.2.1"), id="auto_32"),
+ pytest.param((31, True, "255.255.255.255"), id="auto_31"),
+ pytest.param((30, True, "192.0.2.3"), id="auto_30"),
+ pytest.param((30, False, "192.0.2.2"), id="custom_30"),
+ pytest.param((24, False, "192.0.2.7"), id="custom_24"),
+ ],
+ )
+ def test_add_4_brd(self, brd):
+ """Tests proper broadcast setup when adding IPv4 ifa"""
+ plen, auto_brd, ifa_brd_str = brd
+ ifa = ipaddress.ip_interface("192.0.2.1/{}".format(plen))
+ iface = self.vnet.iface_alias_map["if1"]
+ ifa_brd = ipaddress.ip_address(ifa_brd_str)
+
+ msg = self.create_msg(ifa)
+ msg.add_nla(NlAttrIp(IfaAttrType.IFA_LOCAL, str(ifa.ip)))
+ if not auto_brd:
+ msg.add_nla(NlAttrIp(IfaAttrType.IFA_BROADCAST, str(ifa_brd)))
+
+ self.send_check_success(msg)
+
+ lst = self.get_ifa_list(iface.ifindex, self.get_family_from_ip(ifa.ip))
+ assert len(lst) == 1
+ rx_msg = lst[0]
+
+ assert rx_msg.base_hdr.ifa_prefixlen == ifa.network.prefixlen
+ assert rx_msg.base_hdr.ifa_scope == RtScope.RT_SCOPE_UNIVERSE.value
+
+ assert rx_msg.get_nla(IfaAttrType.IFA_ADDRESS).addr == str(ifa.ip)
+ assert rx_msg.get_nla(IfaAttrType.IFA_LOCAL).addr == str(ifa.ip)
+ assert rx_msg.get_nla(IfaAttrType.IFA_BROADCAST).addr == str(ifa_brd)
+
def test_add_6(self):
ifa = ipaddress.ip_interface("2001:db8::1/64")
iface = self.vnet.iface_alias_map["if1"]