Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 Feb 2004 08:58:59 -0900
From:      =?ISO-8859-1?Q?Andreas_T=F8nnesen?= <andreto@olsr.org>
To:        freebsd-net@freebsd.org
Cc:        vjardin@free.fr
Subject:   Re: Binding sockets to devices in FreeBSD
Message-ID:  <40364AE3.3020204@olsr.org>
In-Reply-To: <20040220000603.29033.qmail@web13606.mail.yahoo.com>
References:  <20040220000603.29033.qmail@web13606.mail.yahoo.com>

next in thread | previous in thread | raw e-mail | index | archive | help
Thanks for your replies mr. Kumar and mr, Jardin.

I've been informed by Bruce Simpson that two interfaces actually cannot 
be configured with the same broadcastaddress in FreeBSD.

Bruce M Simpson wrote:
 >
 > Can't currently do this due to limitations in the routing
 > code (that is, can't have more than one interface with the
 > same netmask and thus broadcast address).

This kind of eliminates the problem... well, atleast until this is 
supported in FreeBSD. But then again BMS suggested using the 
IP_SENDSRCADDR to set the souce of a packet. The routing mechanism
will then transmit the packet in the interface using this address.

But then there is the case where controltraffic could be set to always 
be broadcasted on 255.255.255.255. To be able to control this BMS 
suggested using a kernel hack he'd done where one can set the 
IP_ONESBCAST option and use the broadcastaddress of the interface on 
which one wishes to transmit, the destiantion address will then be set 
to 255.255.255.255 after the packet is routed to a interface.

As for IPv6 I will use the ifindex approach as suggested by mr. Jardin. 
And the fact that this solution seems portable is good news! :-)

I won't start the porting until I've released the 0.4 version, but now 
I've got the strategy planned - and I can start cookin' code in hy head ;-)

Comments on my thoughts on this is welcome!

regards,
Andreas T


Naveen Kumar wrote:
> Well it doesn't look like it would work for IPV4. 
> If you look at the following code there is no place to
> specify the interface index at packet level in send as
> in IPV6. If the broadcast addresses on the different
> interfaces were different then there is no problem the
> sendto would work but if broadcast addresses are the
> same then it wouldn't
> 
> int
> rip_send_packet (caddr_t buf, int size, struct
> sockaddr_in *to, 
> 		 struct interface *ifp, struct connected *connected)
> {
>   int ret, send_sock;
>   struct sockaddr_in sin;
> 
>   if (IS_RIP_DEBUG_PACKET)
>     {
>       char dst[20];
>       if (to)
>         {
>           strcpy(dst, inet_ntoa(to->sin_addr));
>         }
>       else
>         {
>           sin.sin_addr.s_addr = htonl
> (INADDR_RIP_GROUP);
>           strcpy(dst, inet_ntoa(sin.sin_addr));
>         }
>       zlog_info("rip_send_packet %s > %s (%s)",
>                
> inet_ntoa(connected->address->u.prefix4), dst,
> ifp->name);
>     }
>   if (connected->flags & ZEBRA_IFA_SECONDARY)
>     {
>       /*
>        * ZEBRA_IFA_SECONDARY is set on linux when an
> interface is configured
>        * with multiple addresses on the same subnet:
> the first address
>        * on the subnet is configured "primary", and
> all subsequent addresses
>        * on that subnet are treated as "secondary"
> addresses. 
>        * In order to avoid routing-table bloat on
> other rip listeners, 
>        * we do not send out RIP packets with
> ZEBRA_IFA_SECONDARY source addrs.
>        * XXX Since Linux is the only system for which
> the ZEBRA_IFA_SECONDARY
>        * flag is set, we would end up sending a packet
> for a "secondary"
>        * source address on non-linux systems.  
>        */
>       if (IS_RIP_DEBUG_PACKET)
>         zlog_info("duplicate dropped");
>       return 0;
>     }
> 
>   /* Make destination address. */
>   memset (&sin, 0, sizeof (struct sockaddr_in));
>   sin.sin_family = AF_INET;
> #ifdef HAVE_SIN_LEN
>   sin.sin_len = sizeof (struct sockaddr_in);
> #endif /* HAVE_SIN_LEN */
> 
>   /* When destination is specified, use it's port and
> address. */
>   if (to)
>     {
>       sin.sin_port = to->sin_port;
>       sin.sin_addr = to->sin_addr;
>       send_sock = rip->sock;
>     }
>   else
>     {
> 
>       sin.sin_port = htons (RIP_PORT_DEFAULT);
>       sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
> 
>       /*
>        * we have to open a new socket for each packet
> because this
>        * is the most portable way to bind to a
> different source
>        * ipv4 address for each packet. 
>        */
>       send_sock = socket(AF_INET, SOCK_DGRAM, 0);
>       if (send_sock < 0)
>         {
>           zlog_warn("rip_send_packet could not create
> socket %s",
>                     strerror(errno));
>           return -1;
>     }
>       sockopt_broadcast (send_sock);
>       sockopt_reuseaddr (send_sock);
>       sockopt_reuseport (send_sock);
> #ifdef RIP_RECVMSG
>       setsockopt_pktinfo (send_sock);
> #endif /* RIP_RECVMSG */
>       rip_interface_multicast_set(send_sock,
> connected, if_is_pointopoint(ifp));
>     }
> 
>   ret = sendto (send_sock, buf, size, 0, (struct
> sockaddr *)&sin,
> 		sizeof (struct sockaddr_in));
> 
> --- Vincent Jardin <vjardin@free.fr> wrote:
> 
>>Hi,
>>
>>You need to use sendto or sendmsg.
>>
>>For example, with IPv6, Quagga is sending IPv6
>>multicast packet on a per 
>>interface basis. The interface's ifindex is provided
>>into the pktinfo 
>>structure.
>>
>>int
>>ripng_send_packet (caddr_t buf, int bufsize, struct
>>sockaddr_in6 *to,
>>                   struct interface *ifp)
>>{
>>  int ret;
>>  struct msghdr msg;
>>  struct iovec iov;
>>  struct cmsghdr  *cmsgptr;
>>  char adata [256];
>>  struct in6_pktinfo *pkt;
>>  struct sockaddr_in6 addr;
>>
>>  [...]
>>
>>  memset (&addr, 0, sizeof (struct sockaddr_in6));
>>  addr.sin6_family = AF_INET6;
>>#ifdef SIN6_LEN
>>  addr.sin6_len = sizeof (struct sockaddr_in6);
>>#endif /* SIN6_LEN */
>>  addr.sin6_flowinfo = htonl
>>(RIPNG_PRIORITY_DEFAULT);
>>
>> [...]
>>      inet_pton(AF_INET6, RIPNG_GROUP,
>>&addr.sin6_addr);
>>      addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
>> [...]
>>
>>  msg.msg_name = (void *) &addr;
>>  msg.msg_namelen = sizeof (struct sockaddr_in6);
>>  msg.msg_iov = &iov;
>>  msg.msg_iovlen = 1;
>>  msg.msg_control = (void *) adata;
>>  msg.msg_controllen = CMSG_SPACE(sizeof(struct
>>in6_pktinfo));
>>
>>  iov.iov_base = buf;
>>  iov.iov_len = bufsize;
>>
>>  cmsgptr = (struct cmsghdr *)adata;
>>  cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct
>>in6_pktinfo));
>>  cmsgptr->cmsg_level = IPPROTO_IPV6;
>>  cmsgptr->cmsg_type = IPV6_PKTINFO;
>>
>>  pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
>>  memset (&pkt->ipi6_addr, 0, sizeof (struct
>>in6_addr));
>>  pkt->ipi6_ifindex = ifp->ifindex;
>>
>>  ret = sendmsg (ripng->sock, &msg, 0);
>>
>>[...]
>>
>>  return ret;
>>}
>>
>>About IPv4, see the sendto() use case of
>>ripd/ripd.c.
>>
>>Moreover these solutions, which are used by Quagga,
>>are portable on most of 
>>the OSes (Linux, FreeBSD, OpenBSD, NetBSD, Solaris,
>>...).
>>
>>Regards,
>>  Vincent
>>
>>
>>On Thursday 19 February 2004 10:54, Andreas T wrote:
>>
>>>Hi all,
>>>
>>>I am developing an implementation of the Optimized
>>
>>LinkState Routing
>>
>>>protocol(RFC3626) for Linux(www.olsr.org). OLSR is
>>
>>a routing protocol
>>
>>>for mobile, multihop, wireless ad-hoc networks.
>>>
>>>I would really like to have my code compile on
>>
>>FreeBSD - but there is
>>
>>>one major issue.
>>>
>>>OLSR sends control traffic broadcasted(IPv4) or
>>
>>multicasted(IPv6) on a
>>
>>>pr.interface basis. That means that a node running
>>
>>OLSR on two
>>
>>>interfaces a and b, would not always broadcast the
>>
>>same content in
>>
>>>messages sent on a and b. This works fine using
>>
>>IPv4 and broadcast as
>>
>>>long as the interfaces uses different broadcast
>>
>>addresses - but as soon
>>
>>>as two interfaces is set up with the same
>>
>>broadcastaddress(or as soon as
>>
>>>one uses IPv6 with the same multicastgroup) any
>>
>>message (sent on the
>>
>>>broadcastsocket) will be transmitted on both
>>
>>interfaces.
>>
>>>I hope this made some sense :)
>>>
>>>Bottom line is that one has to be able to control
>>
>>on which interface
>>
>>>packets are sent. To do this in Linux i use the
>>
>>SO_BINDTODEVICE
>>
>>>flag(with setsockopt(2)). That way I can have one
>>
>>socket for each
>>
>>>interface OLSR is to use regradless of
>>
>>destinationaddress.
>>
>>>In FreeBSD there is no SO_BINDTODEVICE or
>>
>>equalivant as far as I can
>>
>>>see. To me it seems like BPF could provide the
>>
>>functioning I need. Is
>>
>>>this so? Can BPF in some way help me control on
>>
>>which interface packets
>>
>>>are transmitted?
>>>If so I would really appreciate some (pseudo or
>>
>>real)code examples to
>>
>>>get me started or some links to such material - as
>>
>>I am totally new to
>>
>>>the BPF interface(and the concept).
>>>
>>>If BPF is not the way to go I would appreciate any
>>
>>help in finding a way
>>
>>>of doing this in FreeBSD.
>>>
>>>I could ofcause try to figure this out by myself -
>>
>>but as FreeBSD
>>
>>>porting is not too high prioritized for now I
>>
>>figured I'd rather be lazy
>>
>>>and ask you experts :)
>>>
>>>
>>>Thanks!
>>>
>>>regards,
>>>Andreas T
>>
>>_______________________________________________
>>freebsd-net@freebsd.org mailing list
>>
> 
> http://lists.freebsd.org/mailman/listinfo/freebsd-net
> 
>>To unsubscribe, send any mail to
> 
> "freebsd-net-unsubscribe@freebsd.org"
> 
> 
> 
> __________________________________
> Do you Yahoo!?
> Yahoo! Mail SpamGuard - Read only the mail you want.
> http://antispam.yahoo.com/tools

-- 
Andreas Tønnesen(andreas@olsr.org)
UniK University Graduation Center
University of Oslo
http://www.olsr.org



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?40364AE3.3020204>