Re: [cifs bindaddr v2] cifs: Allow binding to local IP address.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



There are clearly valid reasons for being able to select outgoing
interface - I wouldn't mind doing this using IPv6 address format if
that is more natural (since that can include ipv4 addresses) - or
distinct ipv4/ipv6

On Thu, Aug 26, 2010 at 2:57 PM, Jeff Layton <jlayton@xxxxxxxxx> wrote:
> On Thu, 26 Aug 2010 10:34:56 -0700
> Ben Greear <greearb@xxxxxxxxxxxxxxx> wrote:
>
>> When using multi-homed machines, it's nice to be able to specify
>> the local IP to use for outbound connections.  This patch gives
>> cifs the ability to bind to a particular IP address.
>>
>> Usage:  mount -t cifs -o bindaddr=192.168.1.50,user=foo, ...
>>
>> Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
>> ---
>> :100644 100644 b7431af... 77293db... M        fs/cifs/cifsfs.c
>> :100644 100644 c9d0cfc... c0176d8... M        fs/cifs/cifsglob.h
>> :100644 100644 ec0ea4a... bacbf46... M        fs/cifs/connect.c
>>  fs/cifs/cifsfs.c   |    4 +++
>>  fs/cifs/cifsglob.h |    1 +
>>  fs/cifs/connect.c  |   53 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>>  3 files changed, 56 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
>> index b7431af..77293db 100644
>> --- a/fs/cifs/cifsfs.c
>> +++ b/fs/cifs/cifsfs.c
>> @@ -374,6 +374,10 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
>>       if (tcon->ses->domainName)
>>               seq_printf(s, ",domain=%s", tcon->ses->domainName);
>>
>> +     if (tcon->ses->server->ip4_local_ip)
>> +             seq_printf(s, ",bindaddr=%pI4",
>> +                        &tcon->ses->server->ip4_local_ip);
>> +
>>       seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
>>       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
>>               seq_printf(s, ",forceuid");
>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>> index c9d0cfc..c0176d8 100644
>> --- a/fs/cifs/cifsglob.h
>> +++ b/fs/cifs/cifsglob.h
>> @@ -157,6 +157,7 @@ struct TCP_Server_Info {
>>               struct sockaddr_in sockAddr;
>>               struct sockaddr_in6 sockAddr6;
>>       } addr;
>> +     u32 ip4_local_ip;
>>       wait_queue_head_t response_q;
>>       wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
>>       struct list_head pending_mid_q;
>> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
>> index ec0ea4a..bacbf46 100644
>> --- a/fs/cifs/connect.c
>> +++ b/fs/cifs/connect.c
>> @@ -105,6 +105,7 @@ struct smb_vol {
>>       bool sockopt_tcp_nodelay:1;
>>       unsigned short int port;
>>       char *prepath;
>> +     u32 local_ip; /* allow binding to a local IP address if != 0 */
>>       struct nls_table *local_nls;
>>  };
>>
>> @@ -1064,6 +1065,32 @@ cifs_parse_mount_options(char *options, const char *devname,
>>                                                   "long\n");
>>                               return 1;
>>                       }
>> +             } else if (strnicmp(data, "bindaddr", 8) == 0) {
>> +                     struct sockaddr_storage laddr;
>> +                     memset(&laddr, 0, sizeof(laddr));
>> +
>> +                     if (!value || !*value) {
>> +                             printk(KERN_WARNING "CIFS: bindaddr value"
>> +                                    " not specified.\n");
>> +                             return 1;       /* needs_arg; */
>> +                     }
>> +                     i = cifs_convert_address((struct sockaddr *)(&laddr),
>> +                                              value, strlen(value));
>> +                     if (i < 0) {
>> +                             vol->local_ip = 0;
>> +                             printk(KERN_WARNING "CIFS:  Could not parse"
>> +                                    " bindaddr: %s\n",
>> +                                    value);
>> +                             return 1;
>> +                     } else {
>> +                             struct sockaddr_in *s4;
>> +                             s4 = (struct sockaddr_in *)&laddr;
>> +                             if (s4->sin_family == AF_INET)
>> +                                     vol->local_ip = s4->sin_addr.s_addr;
>> +                             else
>> +                                     printk(KERN_WARNING "WARNING:  IPv6 "
>> +                                            "bindaddr not supported yet.\n");
>> +                     }
>>               } else if (strnicmp(data, "prefixpath", 10) == 0) {
>>                       if (!value || !*value) {
>>                               printk(KERN_WARNING
>> @@ -1393,7 +1420,8 @@ cifs_parse_mount_options(char *options, const char *devname,
>>  }
>>
>>  static bool
>> -match_address(struct TCP_Server_Info *server, struct sockaddr *addr)
>> +match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
>> +           u32 local_ip4)
>>  {
>>       struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
>>       struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
>> @@ -1406,6 +1434,8 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr)
>>               if (addr4->sin_port &&
>>                   addr4->sin_port != server->addr.sockAddr.sin_port)
>>                       return false;
>> +             if (local_ip4 && (local_ip4 != server->ip4_local_ip))
>> +                     return false;
>>               break;
>>       case AF_INET6:
>>               if (!ipv6_addr_equal(&addr6->sin6_addr,
>> @@ -1487,7 +1517,7 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
>>               if (server->tcpStatus == CifsNew)
>>                       continue;
>>
>> -             if (!match_address(server, addr))
>> +             if (!match_address(server, addr, vol->local_ip))
>>                       continue;
>>
>>               if (!match_security(server, vol))
>> @@ -1602,6 +1632,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
>>        * no need to spinlock this init of tcpStatus or srv_count
>>        */
>>       tcp_ses->tcpStatus = CifsNew;
>> +     tcp_ses->ip4_local_ip = volume_info->local_ip;
>>       ++tcp_ses->srv_count;
>>
>>       if (addr.ss_family == AF_INET6) {
>> @@ -1678,6 +1709,10 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
>>                                   vol->password ? vol->password : "",
>>                                   MAX_PASSWORD_SIZE))
>>                               continue;
>> +                     if (server->ip4_local_ip &&
>> +                         (server->ip4_local_ip != ses->server->ip4_local_ip))
>> +                             continue;
>> +                     /* TODO:  Deal with IPv6 local addr matching? --Ben */
>>               }
>>               ++ses->ses_count;
>>               write_unlock(&cifs_tcp_ses_lock);
>> @@ -2051,6 +2086,20 @@ ipv4_connect(struct TCP_Server_Info *server)
>>               cifs_reclassify_socket4(socket);
>>       }
>>
>> +     /* Bind to the local IP address if specified */
>> +     if (server->ip4_local_ip) {
>> +             struct sockaddr_in myaddr = {
>> +                     .sin_family = AF_INET,
>> +             };
>> +             myaddr.sin_addr.s_addr = server->ip4_local_ip;
>> +             myaddr.sin_port = 0; /* any */
>> +             rc = socket->ops->bind(socket, (struct sockaddr *) &myaddr,
>> +                                    sizeof(myaddr));
>> +             if (rc < 0)
>> +                     cERROR(1, "Failed to bind to: %pI4, error: %d\n",
>> +                            &server->ip4_local_ip, rc);
>> +     }
>> +
>>       /* user overrode default port */
>>       if (server->addr.sockAddr.sin_port) {
>>               rc = socket->ops->connect(socket, (struct sockaddr *)
>
>
> I'm not crazy about this patch. It seems like this ought to be the
> purview of the routing table. I know however that there are situations
> where that's not really possible (clusters with floating IP addrs, for
> instance).
>
> That said, even if we were to do something along these lines, it seems
> like it ought to be more transport neutral (i.e. not IPv4 only like
> this patch is).
>
> --
> Jeff Layton <jlayton@xxxxxxxxx>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Thanks,

Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux