From f6cd1560c846609736a9a18b0fe6564475dd54d8 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 5 Jan 2018 15:25:42 +0100 Subject: [PATCH] pimd: support for vrf netns for pimd ( not complete) The changes include the initialisation of the namespace, as well as the switch from context when operating under network sockets. Also it includes the bind to a vrf socket when the vrf is not a vrf lite. Signed-off-by: Philippe Guibert --- pimd/pim_iface.c | 20 +++++++++++++------- pimd/pim_igmp_join.h | 11 +++++++---- pimd/pim_instance.c | 2 ++ pimd/pim_mroute.c | 17 ++++++++++++++--- pimd/pim_sock.c | 14 +++++++++----- pimd/pim_sock.h | 5 +++-- pimd/test_igmpv3_join.c | 4 +++- 7 files changed, 51 insertions(+), 22 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index f02cf7ed31c4..db9b27ff940b 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -50,7 +50,8 @@ static void pim_if_igmp_join_del_all(struct interface *ifp); static int igmp_join_sock(const char *ifname, ifindex_t ifindex, struct in_addr group_addr, - struct in_addr source_addr); + struct in_addr source_addr, + struct vrf *vrf); void pim_if_init(struct pim_instance *pim) { @@ -580,6 +581,7 @@ void pim_if_addr_add(struct connected *ifc) struct listnode *nextnode; struct igmp_join *ij; int join_fd; + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij)) { @@ -588,7 +590,7 @@ void pim_if_addr_add(struct connected *ifc) close(ij->sock_fd); join_fd = igmp_join_sock( ifp->name, ifp->ifindex, ij->group_addr, - ij->source_addr); + ij->source_addr, vrf); if (join_fd < 0) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; @@ -1211,18 +1213,21 @@ static struct igmp_join *igmp_join_find(struct list *join_list, } static int igmp_join_sock(const char *ifname, ifindex_t ifindex, - struct in_addr group_addr, struct in_addr source_addr) + struct in_addr group_addr, + struct in_addr source_addr, struct vrf *vrf) { int join_fd; - join_fd = pim_socket_raw(IPPROTO_IGMP); + join_fd = pim_socket_raw(IPPROTO_IGMP, vrf); if (join_fd < 0) { return -1; } if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, - ifname)) { + ifname, vrf)) { + vrf_switch_to_netns(vrf); close(join_fd); + vrf_switchback_to_initial(); return -2; } @@ -1236,12 +1241,13 @@ static struct igmp_join *igmp_join_new(struct interface *ifp, struct pim_interface *pim_ifp; struct igmp_join *ij; int join_fd; - + struct vrf *vrf; pim_ifp = ifp->info; zassert(pim_ifp); + vrf = vrf_lookup_by_id(ifp->vrf_id); join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, - source_addr); + source_addr, vrf); if (join_fd < 0) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; diff --git a/pimd/pim_igmp_join.h b/pimd/pim_igmp_join.h index abee0800640b..305ab4f40661 100644 --- a/pimd/pim_igmp_join.h +++ b/pimd/pim_igmp_join.h @@ -37,11 +37,13 @@ struct group_source_req { static int pim_igmp_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, - struct in_addr source_addr) + struct in_addr source_addr, + struct vrf *vrf) { struct group_source_req req; struct sockaddr_in group; struct sockaddr_in source; + int ret; memset(&req, 0, sizeof(req)); memset(&group, 0, sizeof(group)); @@ -58,10 +60,11 @@ static int pim_igmp_join_source(int fd, ifindex_t ifindex, req.gsr_interface = ifindex; - return setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &req, + vrf_switch_to_netns(vrf); + ret = setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)); - - return 0; + vrf_switchback_to_initial(); + return ret; } #endif /* PIM_IGMP_JOIN_H */ diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index 8da610a3a6d5..7de9d3ad9533 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -21,6 +21,7 @@ #include #include "hash.h" +#include "ns.h" #include "vrf.h" #include "pimd.h" @@ -211,6 +212,7 @@ static int pim_vrf_config_write(struct vty *vty) void pim_vrf_init(void) { + ns_init(); vrf_init(pim_vrf_new, pim_vrf_enable, pim_vrf_disable, pim_vrf_delete); vrf_cmd_init(pim_vrf_config_write); diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index cb956c003683..c81f40a66347 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -59,10 +59,11 @@ static int pim_mroute_set(struct pim_instance *pim, int enable) zlog_err( "pim_mroute_socket_enable: could not raise privs, %s", safe_strerror(errno)); - + vrf_switch_to_netns(pim->vrf); opt = pim->vrf->data.l.table_id; err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_TABLE, &opt, opt_len); + vrf_switchback_to_initial(); if (err) { zlog_warn( "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s", @@ -78,8 +79,10 @@ static int pim_mroute_set(struct pim_instance *pim, int enable) safe_strerror(errno)); } + vrf_switch_to_netns(pim->vrf); opt = enable ? MRT_INIT : MRT_DONE; err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &opt, opt_len); + vrf_switchback_to_initial(); if (err) { zlog_warn( "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s", @@ -93,6 +96,7 @@ static int pim_mroute_set(struct pim_instance *pim, int enable) if (enable) { /* Linux and Solaris IP_PKTINFO */ opt = 1; + vrf_switch_to_netns(pim->vrf); if (setsockopt(pim->mroute_socket, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) { zlog_warn( @@ -100,15 +104,18 @@ static int pim_mroute_set(struct pim_instance *pim, int enable) pim->mroute_socket, errno, safe_strerror(errno)); } + vrf_switchback_to_initial(); } #endif + vrf_switch_to_netns(pim->vrf); setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8); flags = fcntl(pim->mroute_socket, F_GETFL, 0); if (flags < 0) { zlog_warn("Could not get flags on socket fd:%d %d %s", pim->mroute_socket, errno, safe_strerror(errno)); + vrf_switchback_to_initial(); close(pim->mroute_socket); return -1; } @@ -116,16 +123,20 @@ static int pim_mroute_set(struct pim_instance *pim, int enable) zlog_warn("Could not set O_NONBLOCK on socket fd:%d %d %s", pim->mroute_socket, errno, safe_strerror(errno)); close(pim->mroute_socket); + vrf_switchback_to_initial(); return -1; } + vrf_switchback_to_initial(); if (enable) { #if defined linux int upcalls = IGMPMSG_WRVIFWHOLE; opt = MRT_PIM; + vrf_switch_to_netns(pim->vrf); err = setsockopt(pim->mroute_socket, IPPROTO_IP, opt, &upcalls, sizeof(upcalls)); + vrf_switchback_to_initial(); if (err) { zlog_warn( "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s", @@ -710,9 +721,9 @@ int pim_mroute_socket_enable(struct pim_instance *pim) if (pimd_privs.change(ZPRIVS_RAISE)) zlog_err("pim_mroute_socket_enable: could not raise privs, %s", safe_strerror(errno)); - + vrf_switch_to_netns(pim->vrf); fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); - + vrf_switchback_to_initial(); if (fd < 0) { zlog_warn("Could not create mroute socket: errno=%d: %s", errno, safe_strerror(errno)); diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index b75d0cc9789d..2bdf94754e65 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -42,15 +42,16 @@ /* GLOBAL VARS */ -int pim_socket_raw(int protocol) +int pim_socket_raw(int protocol, struct vrf *vrf) { int fd; if (pimd_privs.change(ZPRIVS_RAISE)) zlog_err("pim_sockek_raw: could not raise privs, %s", safe_strerror(errno)); - + vrf_switch_to_netns(vrf); fd = socket(AF_INET, SOCK_RAW, protocol); + vrf_switchback_to_initial(); if (pimd_privs.change(ZPRIVS_LOWER)) zlog_err("pim_socket_raw: could not lower privs, %s", @@ -116,8 +117,10 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, struct ip_mreq mreq; #endif int fd; + struct vrf *vrf; - fd = pim_socket_raw(protocol); + vrf = vrf_lookup_by_id(ifp->vrf_id); + fd = pim_socket_raw(protocol, vrf); if (fd < 0) { zlog_warn("Could not create multicast socket: errno=%d: %s", errno, safe_strerror(errno)); @@ -323,9 +326,10 @@ int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, } int pim_socket_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, - struct in_addr source_addr, const char *ifname) + struct in_addr source_addr, + const char *ifname, struct vrf *vrf) { - if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) { + if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr, vrf)) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; pim_inet4_dump("", group_addr, group_str, diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index 358dd39a44de..633043bd77d8 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -37,13 +37,14 @@ int pim_socket_bind(int fd, struct interface *ifp); void pim_socket_ip_hdr(int fd); -int pim_socket_raw(int protocol); +int pim_socket_raw(int protocol, struct vrf *vrf); int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp, u_char loop); int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, ifindex_t ifindex); int pim_socket_join_source(int fd, ifindex_t ifindex, struct in_addr group_addr, - struct in_addr source_addr, const char *ifname); + struct in_addr source_addr, + const char *ifname, struct vrf *vrf); int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, diff --git a/pimd/test_igmpv3_join.c b/pimd/test_igmpv3_join.c index bf44f3c94a47..da8962629e80 100644 --- a/pimd/test_igmpv3_join.c +++ b/pimd/test_igmpv3_join.c @@ -29,6 +29,7 @@ #include #include +#include "vrf.h" #include "if.h" #include "pim_igmp_join.h" @@ -124,7 +125,8 @@ int main(int argc, const char *argv[]) exit(1); } - result = pim_igmp_join_source(fd, ifindex, group_addr, source_addr); + result = pim_igmp_join_source(fd, ifindex, group_addr, + source_addr, NULL); if (result) { fprintf(stderr, "%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s\n",