Closed vasu-dasari closed 6 years ago
I tried the following snippet, but, bind function returns {error,eafnosupport}
:
I do get right IfIndex(in my case case 8) via packet:ifindex(Fd,"veth1")
. Just that bind is failing.
{ok,Port} = gen_udp:open(0,[{netns,"/var/run/netns/blue"}]),
packet:bind(inet:getfd(Port), packet:ifindex(Fd,"veth1")),
Commands I have used to create namespace:
ip netns add blue
ip link add veth0 type veth peer name veth1
ip link set veth1 netns blue
ip netns exec blue ifconfig veth1 10.1.1.1/24 up
ifconfig veth0 10.1.1.100/24 up
This is a great question. About the failure: we're returned the {error, eafnosupport}
tuple because we're attempting to bind an AF_INET socket. packet:bind/2 expects an AF_PACKET socket. If we try specifying an AF_INET socket:
1> {ok,Port} = gen_udp:open(0,[{netns,"/var/run/netns/blue"}]).
{ok,#Port<0.37928>}
2> {ok, Fd} = inet:getfd(Port).
{ok,12}
3> Ifindex = packet:ifindex(Fd,"veth1").
6
4> packet:bind(Fd, Ifindex).
{error,eafnosupport}
5> SA = <<2:16/native, 0:16, 6:32/native, 0:96>>.
<<2,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>
6> procket:bind(Fd, SA).
{error,eaddrnotavail}
For namespace support, we'd probably want to support any type of socket.
1> {ok, S} = procket:open(0, [{protocol, 16#0008}, {type, raw}, {family, packet}, {namespace, "/var/run/netns/blue"}]).
{ok,14}
2> {ok, Q} = procket:read(S, 16#ffff).
{ok,<<1,0,94,0,0,251,246,255,141,18,35,1,8,0,69,0,0,68,
51,22,64,0,1,17,90,51,10,...>>}
3> pkt:decode(Q).
{ok,{[{ether,<<1,0,94,0,0,251>>,
<<246,255,141,18,35,1>>,
2048,0},
{ipv4,4,5,0,68,13078,1,0,0,1,17,23091,
{10,1,1,100},
{224,0,0,251},
<<>>},
{udp,5353,5353,48,60577}],
<<0,0,0,0,0,1,0,0,0,0,0,0,11,95,103,111,111,103,108,101,
99,97,115,116,4,...>>}}
Here is patch to support namespaces (without tests or portability goop):
diff --git a/c_src/procket.h b/c_src/procket.h
index ec7c9b7..30646b2 100644
--- a/c_src/procket.h
+++ b/c_src/procket.h
@@ -82,6 +82,7 @@ typedef struct {
char *port; /* Port */
char *ifname; /* network interface name */
char *dev; /* Open a character device */
+ char *ns; /* Open a namespace */
int verbose; /* Debug messages */
int s; /* socket fd */
int family; /* socket family: PF_INET */
diff --git a/c_src/procket_cmd.c b/c_src/procket_cmd.c
index 9078043..5eda94e 100644
--- a/c_src/procket_cmd.c
+++ b/c_src/procket_cmd.c
@@ -29,12 +29,15 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define _GNU_SOURCE
+#include <sched.h>
+
#include "procket.h"
#include "ancillary.h"
-
#define BACKLOG 128 /* default backlog for TCP connections */
+int procket_open_ns(PROCKET_STATE *ps);
int procket_open_fd(PROCKET_STATE *ps);
int procket_check_devname(char *dev, size_t len);
int procket_pipe(PROCKET_STATE *ps);
@@ -72,7 +75,7 @@ main(int argc, char *argv[])
ps->fdtype = PROCKET_FD_SOCKET;
- while ( (ch = getopt(argc, argv, "b:d:F:hI:p:P:T:u:v")) != -1) {
+ while ( (ch = getopt(argc, argv, "b:d:F:hI:N:p:P:T:u:v")) != -1) {
switch (ch) {
case 'b': /* listen backlog */
ps->backlog = atoi(optarg);
@@ -124,6 +127,12 @@ main(int argc, char *argv[])
ps->fdtype = PROCKET_FD_CHARDEV;
break;
+ case 'N': /* namespace */
+ ps->ns = strdup(optarg);
+
+ if (ps->ns == NULL)
+ error_result(ps, errno);
+ break;
case 'v':
ps->verbose++;
break;
@@ -149,6 +158,9 @@ main(int argc, char *argv[])
error_result(ps, ENAMETOOLONG);
}
+ if (procket_open_ns(ps) < 0)
+ error_result(ps, errno);
+
if (procket_open_fd(ps) < 0)
error_result(ps, errno);
@@ -161,6 +173,24 @@ main(int argc, char *argv[])
exit(0);
}
+ int
+procket_open_ns(PROCKET_STATE *ps)
+{
+ int fd = 0;
+
+ if (ps->ns == NULL)
+ return 0;
+
+ fd = open(ps->ns, O_RDONLY);
+
+ if (fd < 0)
+ return -1;
+
+ if (setns(fd, 0 /* join all namespaces */) < 0)
+ return -1;
+
+ return 0;
+}
int
procket_open_fd(PROCKET_STATE *ps)
diff --git a/src/procket.erl b/src/procket.erl
index fc9f488..993cdd2 100644
--- a/src/procket.erl
+++ b/src/procket.erl
@@ -435,6 +435,9 @@ optarg({dev, Dev}) when is_list(Dev) ->
erlang:error(badarg, [{dev, Dev}])
end;
+optarg({namespace, NS}) when is_list(NS) ->
+ switch("N", NS);
+
% Ignore any other arguments
optarg(_Arg) ->
"".
Thanks. Actually, I have a patch which is working. I just did a pull request can you take a look?
Hello,
Is there a way I can specify network namespace to use for the socket? For example, gen_udp/gen_tcp has an option to specify netns via {netns,NS} tuple. Is there anything similar to that while using procket? If this is achieved by some other means, can someone point me to the fist or snippet?
Thanks -Vasu