Page MenuHomeFreeBSD

IPv6 transport for bsnmp
ClosedPublic

Authored by harti on Aug 10 2018, 9:44 AM.

Details

Summary

This patch adds a new table begemotSnmpdTransInetTable that uses the InetAddressType textual convention and can be used to create listening ports for IPv4, IPv6, zoned IPv6 and based on DNS names. It also supports future extension beyond UDP by adding a protocol identifier to the table index.

In order to support this gensnmptree had to be modified.

Test Plan

This needs testing one more realistic IPv6 environments. Especially the ipv6z and dns address types need some testing.

Diff Detail

Repository
rS FreeBSD src repository
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

harti created this revision.Aug 10 2018, 9:44 AM
bz added a subscriber: bz.Aug 10 2018, 10:19 AM

I've only scrolled through. I really don't get why ipv6z (needless to say ipv4z is defined but not used) needs to be special. The fact that we encode the interface index is unhelpful in a config file as that might change between boots or other operations, such as oder of vnet creation, order of interface creation, etc.

ae added a subscriber: ae.Aug 10 2018, 10:27 AM
ae added inline comments.
contrib/bsnmp/snmpd/trans_inet.c
698 ↗(On Diff #46500)

Maybe memcpy() will be better?
Also we can check that address is link-local and print warning about ambiguous address, or return error and suggest to use ipv6z type?

762 ↗(On Diff #46500)

It would be good to show scope zone index here too. Or its string representation from getnameinfo() or if_indextoname().

840 ↗(On Diff #46500)

What about ipi6_ifindex?

865 ↗(On Diff #46500)

It looks like you have not enough information for pktinfo structure here. For zoned addresses you need to specify scope zone id via ipi6_ifindex field, but its value was not saved.

914 ↗(On Diff #46500)

I think we can just use memcpy() here.

917 ↗(On Diff #46500)

And here.

ae added a comment.Aug 10 2018, 10:37 AM

Hi, Harti, while I was on the vacation, you made the patch :)
You can take a look to what I did before the vacation https://people.freebsd.org/~ae/bsnmpd_ipv6.diff
It is incomplete, but I started to make it differently. Maybe you will find something interesting.

In D16654#353961, @bz wrote:

I've only scrolled through. I really don't get why ipv6z (needless to say ipv4z is defined but not used) needs to be special. The fact that we encode the interface index is unhelpful in a config file as that might change between boots or other operations, such as oder of vnet creation, order of interface creation, etc.

The definition for InetAddressType comes from RFC4001 and I decided to use that instead of rolling our own. Since we have nothing like ipv4z, its not supported in the new table. ipv6z is.

Sure the interface index is not the best thing in a config file, but this is how all the interface-related stuff in SNMP works. The primary key is the interface index. As far as I understand it was once supposed to be constant even through reboots, but this is obviously not the case anymore. I see several options to make this more useable:

  • use the dns(16) address type. This allows using interface names for the scope of link local addresses.
  • add functions to the config parser. One function might resolve interface names or descriptions to interfaces indexes.
  • add functionality for GET/GETNEXT to the config parser. This is more tricky than it seems since this requires more control of the initialization order.

The near term plan would be to implement the config functions.

There is some mechanism in mibII to make interface indexes constant during operation by using the MAC address as a key. This makes operating system interface indexes and SNMP interface indexes differ, and I don't like the complexity of this. I also doubt that it is useful and have a plan to not implement this in a new version of mibII.

In D16654#353982, @ae wrote:

Hi, Harti, while I was on the vacation, you made the patch :)
You can take a look to what I did before the vacation https://people.freebsd.org/~ae/bsnmpd_ipv6.diff
It is incomplete, but I started to make it differently. Maybe you will find something interesting.

Hi Andrey,

yeah, I completly forgot about the client side.

Adding a new SNMP syntax is probably not the best thing to do because clients will not understand it. Making an extra table for IPv6 is surely an option, but then I thought that with the RFC4001 stuff one gets even more functionality (the dns-type addresses).

If its ok, I integrated some of your client-side stuff?

Regards,
harti

Hi Andrey, some comments on your comments :-)

contrib/bsnmp/snmpd/trans_inet.c
698 ↗(On Diff #46500)

Ok, memcpy() is better.

I'm not an expert with the IPv6 API. Do you mean that a link-local address always needs a scope_id? Seems reasonable...

762 ↗(On Diff #46500)

OK. I'll do that.

840 ↗(On Diff #46500)

The info I found about the PKTINFO was not to helpful :-(. So in addition to the source address we also need the interface index?

865 ↗(On Diff #46500)

Ok.

914 ↗(On Diff #46500)

Ok.

917 ↗(On Diff #46500)

Not really if we want to stay endian-independent. We need to make an uint32_t out of 4 big-endian bytes.

philip added a subscriber: philip.Aug 12 2018, 4:26 AM
philip requested changes to this revision.Aug 12 2018, 4:45 AM

Thanks for this patch, @harti! I've just scrolled through it and added some minor observations in addition to the things @ae pointed out.

contrib/bsnmp/gensnmptree/gensnmptree.c
126 ↗(On Diff #46500)

This introduces a typo.

contrib/bsnmp/snmpd/main.c
1043 ↗(On Diff #46500)

Use INET6_ADDRSTRLEN here?

contrib/bsnmp/snmpd/trans_inet.c
698 ↗(On Diff #46500)

Yes: a link-local address always needs an interface identifier. The same link-local address can exist (on the machine even!) on different networks. Without the interface identifier, a link local address is ambiguous.

This revision now requires changes to proceed.Aug 12 2018, 4:45 AM
ae added a comment.Aug 12 2018, 4:44 PM

Sure the interface index is not the best thing in a config file, but this is how all the interface-related stuff in SNMP works. The primary key is the interface index. As far as I understand it was once supposed to be constant even through reboots, but this is obviously not the case anymore. I see several options to make this more useable:

  • use the dns(16) address type. This allows using interface names for the scope of link local addresses.
  • add functions to the config parser. One function might resolve interface names or descriptions to interfaces indexes.
  • add functionality for GET/GETNEXT to the config parser. This is more tricky than it seems since this requires more control of the initialization order.

I thought to use only following form of IPv6 addresses in config file:

+begemotSnmpdInet6PortStatus.[$(host)].161 = 1
+begemotSnmpdInet6PortStatus.[::1].161 = 1
+begemotSnmpdInet6PortStatus.[fe80::1%igb0].161 = 1
+begemotSnmpdInet6PortStatus.[2002::dead:c0de::1].161 = 1

But this variant only expects IPv6 addresses for begemotSnmpdInet6PortStatus. In your case I think we can check if it is IPv4 addres, then if it IPv6 address, and then if it is host name.

ae added inline comments.Aug 12 2018, 4:52 PM
contrib/bsnmp/snmpd/trans_inet.c
840 ↗(On Diff #46500)

For ambiguous addresses, like IPv6 link-local, you need to specify ifindex, without it the send() will fail in most cases. For global IPv6 addresses interface will be determined from routing table.

harti updated this revision to Diff 46767.Aug 16 2018, 12:13 PM

Use memcpy() in some places.
Save and use the complete in6_pktinfo.
Check that link local addresses have a non-zero scope and produce a warning if not.
Add upd6 and ipv6 address format for server specification.
Factor out common creation code for ipv6 and ipv6z.
Fix a type in gensnmptree.

harti marked 16 inline comments as done.Aug 16 2018, 12:16 PM

Updated diff and marked comments as done.

ae added inline comments.Aug 16 2018, 1:20 PM
contrib/bsnmp/lib/snmpclient.c
1967 ↗(On Diff #46767)

Actually IPv6 address length can be longer than INET6_ADDRSTRLEN.
This constant covers the length of address 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255\0'
But IPv6 link-local address can have additional zone specifier, i.e. '%' and IF_NAMESIZE.
So, I would use INET6_ADDRSTRLEN+IF_NAMESIZE as maximum length.

ae added a comment.Aug 16 2018, 1:22 PM

I'll try to use this patch in several days and will report.

ae added a comment.Aug 27 2018, 10:58 AM

Hi, Harti, can you upload the full patch that contains Makefile changes? :)

ae added inline comments.Aug 27 2018, 8:37 PM
contrib/bsnmp/snmpd/trans_inet.c
865 ↗(On Diff #46500)

I tried this and it fails with global addresses, due this code in the kernel. The kernel expects that application wants to send trough exactly specified interface if ipi6_ifindex is not zero. And it returns EADDRNOTAVAIL if specified address is not found on specified interface. So, the correct usage should be something like this:

--- a/contrib/bsnmp/snmpd/trans_inet.c
+++ b/contrib/bsnmp/snmpd/trans_inet.c
@@ -864,8 +864,10 @@ ipv6_parse_ctrl(struct port_sock *sock, const struct msghdr *msg)
                        const struct in6_pktinfo *info =
                            (const struct in6_pktinfo *)(const void *)
                            CMSG_DATA(cmsg);
-                       sock->ret_source.a6 = *info;
-
+                       sock->ret_source.a6.ipi6_addr = info->ipi6_addr;
+                       sock->ret_source.a6.ipi6_ifindex =
+                           !IN6_IS_ADDR_LINKLOCAL(&info->ipi6_addr) ? 0:
+                           info->ipi6_ifindex;
                } else if (cmsg->cmsg_level == SOL_SOCKET &&
                    cmsg->cmsg_type == SCM_CREDS) {
                        cred = (struct sockcred *)(void *)CMSG_DATA(cmsg);

However, while testing your patch I found some strange behavior. I will investigate it deeper, and then report.

ae added inline comments.Aug 28 2018, 8:13 AM
contrib/bsnmp/lib/snmpclient.c
2273 ↗(On Diff #46767)

Add udp6 support to bsnmpwalk:

--- a/contrib/bsnmp/lib/snmpclient.c
+++ b/contrib/bsnmp/lib/snmpclient.c
@@ -929,7 +929,8 @@ open_client_udp(const char *host, const char *port)
        /* open connection */
        memset(&hints, 0, sizeof(hints));
        hints.ai_flags = AI_CANONNAME;
-       hints.ai_family = AF_INET;
+       hints.ai_family = snmp_client.trans == SNMP_TRANS_UDP ? AF_INET:
+           AF_INET6;
        hints.ai_socktype = SOCK_DGRAM;
        hints.ai_protocol = 0;
        error = getaddrinfo(snmp_client.chost, snmp_client.cport, &hints, &res0);
@@ -1073,6 +1074,7 @@ snmp_open(const char *host, const char *port, const char *readcomm,
        switch (snmp_client.trans) {
 
          case SNMP_TRANS_UDP:
+         case SNMP_TRANS_UDP6:
                if (open_client_udp(host, port) != 0)
                        return (-1);
                break;
ae added inline comments.Aug 28 2018, 10:00 AM
contrib/bsnmp/lib/snmpclient.c
1977 ↗(On Diff #46767)

inet_pton() fails to parse link-local addresses with specified scope zone indentifier

--- a/contrib/bsnmp/lib/snmpclient.c
+++ b/contrib/bsnmp/lib/snmpclient.c
@@ -39,6 +39,7 @@
 #include <sys/queue.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <net/if.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -1951,6 +1954,10 @@ get_comm(struct snmp_client *sc, const char **strp)
static inline const char *
 get_ipv6(struct snmp_client *sc, const char **strp)
 {
+       char str[INET6_ADDRSTRLEN + IF_NAMESIZE];
+       struct addrinfo hints, *res;
+       int error;
+
        if (**strp != '[')
                return (*strp + 1);
 
@@ -1964,21 +1971,25 @@ get_ipv6(struct snmp_client *sc, const char **strp)
                p++;
        }
 
-       if (p - *strp > INET6_ADDRSTRLEN + 1) {
+       if (p - *strp > INET6_ADDRSTRLEN + IF_NAMESIZE) {
                seterr(sc, "IPv6 address too long '%.*s'", p - *strp, *strp);
                return (NULL);
        }
 
-       char str[INET6_ADDRSTRLEN + 1];
        strncpy(str, *strp + 1, p - (*strp + 1));
        str[p - (*strp + 1)] = '\0';
 
-       struct in6_addr addr;
-       if (inet_pton(AF_INET6, str, &addr) != 1) {
-               seterr(sc, "illegal IPv6 address '%s'", str);
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_flags = AI_CANONNAME | AI_NUMERICHOST;
+       hints.ai_family = AF_INET6;
+       hints.ai_socktype = SOCK_DGRAM;
+       hints.ai_protocol = IPPROTO_UDP;
+       error = getaddrinfo(str, NULL, &hints, &res);
+       if (error != 0) {
+               seterr(sc, "%s: %s", str, gai_strerror(error));
                return (NULL);
        }
-
+       freeaddrinfo(res);
        *strp = p + 1;
        return (p);
 }
ae added inline comments.Aug 28 2018, 11:01 AM
contrib/bsnmp/snmpd/trans_inet.c
865 ↗(On Diff #46500)

However, while testing your patch I found some strange behavior. I will investigate it deeper, and then report.

This problem can be reproduced with sending packets to local IPv6 LLA address. It is unrelated to your patch, I think it is the kernel bug.
I tried to send request to address configured on local interface ix0: fe80::225:90ff:fef9:3c92%ix0
snmpd reports:

snmpd[15477]: send*: No route to host

dtrace script shows that

i 17  27904                ip6_output:return 65
 17  18809                 udp6_send:return 65

And in the same time the following statistics counter grows:

# netstat -sp ip6 | grep "scope rule"
	171 packets that violated scope rules

I suspect that the problem is due to ip6_pktinfo structure attached to the packet in some time is overridden, and scope zone of interface determined via routing table (should be loopback interface) violates with scope specified in pktinfo.

ae added a comment.Aug 30 2018, 2:24 PM

So, I finally found the cause of strange behavior. It is due to the route caching. Reverting of this change makes it working https://svnweb.freebsd.org/base/head/sys/netinet6/udp6_usrreq.c?r1=304545&r2=304713

The problem is that when several packets are sending, after first packet inpcb caches the route via loopback interface and then uses rt_ifp as ifp.
I patched ip6_output() to printf some information for each packet:

--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/socketvar.h>
 #include <sys/syslog.h>
 #include <sys/ucred.h>
+#include <sys/sbuf.h>
 
 #include <machine/in_cksum.h>
 
@@ -582,6 +583,27 @@ again:
         * The outgoing interface must be in the zone of source and
         * destination addresses.
         */
+       {
+               char ip6buf[INET6_ADDRSTRLEN];
+               struct sbuf *sb;
+
+               sb = sbuf_new_auto();
+               sbuf_printf(sb, "%s: src %s, ", __func__,
+                   ip6_sprintf(ip6buf, &ip6->ip6_src));
+               sbuf_printf(sb, "dst %s, ",
+                   ip6_sprintf(ip6buf, &ip6->ip6_dst));
+               sbuf_printf(sb, "ifp %s", ifp->if_xname);
+               if (ro->ro_rt)
+                       sbuf_printf(sb, ", rt_ifp %s",
+                           ro->ro_rt->rt_ifp->if_xname);
+               if (inp)
+                       sbuf_printf(sb, ", ro %p, inp_route6 %p",
+                           ro, &inp->inp_route6);
+               sbuf_putc(sb, '\n');
+               sbuf_finish(sb);
+               sbuf_putbuf(sb);
+               sbuf_delete(sb);
+       }
        origifp = ifp;
 
        src0 = ip6->ip6_src;

The result:

01: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffff80104203300, inp_route6 0xfffff80104203300
02: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffff801309f9300, inp_route6 0xfffff801309f9300
03: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp lo0, rt_ifp lo0, ro 0xfffff80104203300, inp_route6 0xfffff80104203300
snmpd[891]: send*: No route to host
04: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp lo0, rt_ifp lo0, ro 0xfffff801309f9300, inp_route6 0xfffff801309f9300

Note, lo0 has scopeid 0x3, and ix0 has scopeid 0x1.

In the line_01 ip6_output does first route lookup that is saved in inpcb, in the line_03 the cached route is used and the result is scope zone violation with EHOSTUNREACH error.
The lines 02 and 04 are for client socket with the same error bsnmpwalk: Snmp dialog: No route to host. For the line_02 I see the { GetNextRequest(23) R=0 .1.3.6.1.2.1.25 } } request in tcpdump -ni lo0 udp output.

With reverted change in udp6_usrreq.c I got this result:

Aug 30 14:20:08 test15 kernel: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffffe104938e4d8, inp_route6 0xfffff801149f2cf0
Aug 30 14:20:08 test15 kernel: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffffe10492da4c8, inp_route6 0xfffff80114a2d4a8
Aug 30 14:20:08 test15 kernel: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffffe104938e4d8, inp_route6 0xfffff801149f2cf0
Aug 30 14:20:08 test15 kernel: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffffe10492da4c8, inp_route6 0xfffff80114a2d4a8
Aug 30 14:20:08 test15 kernel: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffffe104938e4d8, inp_route6 0xfffff801149f2cf0
Aug 30 14:20:08 test15 kernel: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffffe10492da4c8, inp_route6 0xfffff80114a2d4a8
Aug 30 14:20:08 test15 kernel: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffffe104938e4d8, inp_route6 0xfffff801149f2cf0
Aug 30 14:20:08 test15 kernel: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffffe10492da4c8, inp_route6 0xfffff80114a2d4a8
Aug 30 14:20:08 test15 kernel: ip6_output: src fe80:1::225:90ff:fef9:3c92, dst fe80:1::225:90ff:fef9:3c92, ifp ix0, rt_ifp lo0, ro 0xfffffe104938e4d8, inp_route6 0xfffff801149f2cf0
# tcpdump -ni lo0 udp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
14:27:42.084482 IP6 fe80::225:90ff:fef9:3c92.25206 > fe80::225:90ff:fef9:3c92.161:  C="aish117" GetNextRequest(24)  .1.3.6.1.2.1.25.1
14:27:42.097568 IP6 fe80::225:90ff:fef9:3c92.161 > fe80::225:90ff:fef9:3c92.25206:  C="aish117" GetResponse(29)  .1.3.6.1.2.1.25.1.1.0=52022
14:27:42.110651 IP6 fe80::225:90ff:fef9:3c92.25206 > fe80::225:90ff:fef9:3c92.161:  C="aish117" GetNextRequest(26)  .1.3.6.1.2.1.25.1.1.0
14:27:42.123738 IP6 fe80::225:90ff:fef9:3c92.161 > fe80::225:90ff:fef9:3c92.25206:  C="aish117" GetResponse(37)  .1.3.6.1.2.1.25.1.2.0=07_e2_08_1e_0e_1b_2a_01_2b_00_00
14:27:42.136825 IP6 fe80::225:90ff:fef9:3c92.25206 > fe80::225:90ff:fef9:3c92.161:  C="aish117" GetNextRequest(26)  .1.3.6.1.2.1.25.1.2.0
14:27:42.149912 IP6 fe80::225:90ff:fef9:3c92.161 > fe80::225:90ff:fef9:3c92.25206:  C="aish117" GetResponse(27)  .1.3.6.1.2.1.25.1.3.0=0
14:27:42.162999 IP6 fe80::225:90ff:fef9:3c92.25206 > fe80::225:90ff:fef9:3c92.161:  C="aish117" GetNextRequest(26)  .1.3.6.1.2.1.25.1.3.0
# dtrace -n 'fbt::nd6_output_ifp:entry {printf("%s %s", args[0]->if_xname, args[1]->if_xname);}'
dtrace: description 'fbt::nd6_output_ifp:entry ' matched 1 probe
CPU     ID                    FUNCTION:NAME
 19  40912             nd6_output_ifp:entry lo0 ix0
 16  40912             nd6_output_ifp:entry lo0 ix0
 19  40912             nd6_output_ifp:entry lo0 ix0
 16  40912             nd6_output_ifp:entry lo0 ix0
 19  40912             nd6_output_ifp:entry lo0 ix0
 16  40912             nd6_output_ifp:entry lo0 ix0
 19  40912             nd6_output_ifp:entry lo0 ix0
 16  40912             nd6_output_ifp:entry lo0 ix0
contrib/bsnmp/snmpd/trans_inet.c
767 ↗(On Diff #46767)

IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)

ae added a comment.Aug 31 2018, 7:53 AM

So, local TCP communications using IPv6 link-local addresses also affected by routing caching. Note, should be used addresses that are configured on non-loopback interfaces.
Simple test:

# ifconfig ix0 | grep scopeid
	inet6 fe80::225:90ff:fef9:3c92%ix0 prefixlen 64 scopeid 0x1 
# netstat -sp ip6 | grep "scope rules"
	22 packets that violated scope rules
# nc -l -6 fe80::225:90ff:fef9:3c92%ix0 5678

second console:

# nc -6 fe80::225:90ff:fef9:3c92%ix0 5678
TEST
TEST2
# dtrace -n 'fbt::ip6_output:return {printf("%d", arg1);}'
dtrace: description 'fbt::ip6_output:return ' matched 1 probe
CPU     ID                    FUNCTION:NAME
 12  27904                ip6_output:return 65
 12  27904                ip6_output:return 65
  0  27904                ip6_output:return 65
  0  27904                ip6_output:return 65
# netstat -sp ip6 | grep "scope rules"
	35 packets that violated scope rules

I believe I understand the issue with route caching. in6_selectroute_fib checks for loopback,and substitutes the interface with the local address. ip6_output doesn't need to know that interface, it should just skip the scope check in that case. I'll email a possible kernel patch to Andrey and Harti.

ae added inline comments.Sep 4 2018, 1:47 PM
contrib/bsnmp/snmpd/trans_inet.c
650 ↗(On Diff #46767)

msg->msg_controllen must be initialized first, otherwise CMSF_FIRSTHDR() will return NULL.

890 ↗(On Diff #46767)

The same bug.

--- a/contrib/bsnmp/snmpd/trans_inet.c
+++ b/contrib/bsnmp/snmpd/trans_inet.c
@@ -647,16 +647,17 @@ ipv4_parse_ctrl(struct port_sock *sock, const struct msghdr *msg)
 static void
 ipv4_setsrc(struct port_sock *sock, struct msghdr *msg)
 {
-       struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+       struct cmsghdr *cmsg;
+
+       msg->msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
 
        /* select outgoing interface by setting source address */
+       cmsg = CMSG_FIRSTHDR(msg);
        cmsg->cmsg_level = IPPROTO_IP;
        cmsg->cmsg_type = IP_SENDSRCADDR;
        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
        memcpy(CMSG_DATA(cmsg), &sock->ret_source.a4,
            sizeof(struct in_addr));
-
-       msg->msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
 }
 
 /**
@@ -889,16 +890,17 @@ ipv6_parse_ctrl(struct port_sock *sock, const struct msghdr *msg)
 static void
 ipv6_setsrc(struct port_sock *sock, struct msghdr *msg)
 {
-       struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+       struct cmsghdr *cmsg;
+
+       msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
 
        /* select outgoing interface by setting source address */
+       cmsg = CMSG_FIRSTHDR(msg);
        cmsg->cmsg_level = IPPROTO_IPV6;
        cmsg->cmsg_type = IPV6_PKTINFO;
        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
        memcpy(CMSG_DATA(cmsg), &sock->ret_source.a6,
            sizeof(struct in6_pktinfo));
-
-       msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
 }
 
 /**
ae added a comment.Sep 20 2018, 12:41 PM

Hi, Harti, we have used IPv6 transport several weeks now, and it seems all works good. Do you want to see the full final patch that we use?

harti added a comment.Sep 20 2018, 2:08 PM
In D16654#367736, @ae wrote:

Hi, Harti, we have used IPv6 transport several weeks now, and it seems all works good. Do you want to see the full final patch that we use?

Hi Andrey, yes this would be very helpful. Now that I'm back from vacation I should be able to finish this work.

ae added a comment.Oct 22 2018, 9:59 AM

Hi, Harti, it is good time to commit the IPv6 support into head/ :)

In D16654#376845, @ae wrote:

Hi, Harti, it is good time to commit the IPv6 support into head/ :)

Hi Andrey,

unfortunately I'm completely busy with the kick-off of a large project taking place this week in the last weeks:-/. If somebody could help...

harti

This revision was not accepted when it landed; it landed in state Needs Review.Apr 2 2019, 12:50 PM
Closed by commit rS345797: Add IPv6 transport for bsnmp. (authored by ae). · Explain Why
This revision was automatically updated to reflect the committed changes.