diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 182faf0038..8533c1b12c 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -55,7 +55,7 @@ #define OSPF6_VTY_PORT 2606 /* ospf6d privileges */ -zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND}; +zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_SYS_ADMIN}; struct zebra_privs_t ospf6d_privs = { #if defined(FRR_USER) @@ -68,7 +68,7 @@ struct zebra_privs_t ospf6d_privs = { .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, - .cap_num_p = 2, + .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; /* ospf6d options, we use GNU getopt library. */ @@ -86,6 +86,7 @@ static void __attribute__((noreturn)) ospf6_exit(int status) if (ospf6) { vrf = vrf_lookup_by_id(ospf6->vrf_id); + ospf6_serv_close(&ospf6->fd); ospf6_delete(ospf6); ospf6 = NULL; } else @@ -101,7 +102,6 @@ static void __attribute__((noreturn)) ospf6_exit(int status) ospf6_asbr_terminate(); ospf6_lsa_terminate(); - ospf6_serv_close(); /* reverse access_list_init */ access_list_reset(); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 4830b38a66..eb8c414d9b 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1532,10 +1532,14 @@ int ospf6_receive(struct thread *thread) struct iovec iovector[2]; struct ospf6_interface *oi; struct ospf6_header *oh; + struct ospf6 *ospf6; /* add next read thread */ + ospf6 = THREAD_ARG(thread); sockfd = THREAD_FD(thread); - thread_add_read(master, ospf6_receive, NULL, sockfd, NULL); + + thread_add_read(master, ospf6_receive, ospf6, ospf6->fd, + &ospf6->t_ospf6_receive); /* initialize */ memset(&src, 0, sizeof(src)); @@ -1548,7 +1552,7 @@ int ospf6_receive(struct thread *thread) iovector[1].iov_len = 0; /* receive message */ - len = ospf6_recvmsg(&src, &dst, &ifindex, iovector); + len = ospf6_recvmsg(&src, &dst, &ifindex, iovector, sockfd); if (len > iobuflen) { flog_err(EC_LIB_DEVELOPMENT, "Excess message read"); return 0; @@ -1696,9 +1700,13 @@ static void ospf6_send(struct in6_addr *src, struct in6_addr *dst, } /* send message */ - len = ospf6_sendmsg(src, dst, &oi->interface->ifindex, iovector); - if (len != ntohs(oh->length)) - flog_err(EC_LIB_DEVELOPMENT, "Could not send entire message"); + if (oi->area->ospf6->fd != -1) { + len = ospf6_sendmsg(src, dst, &oi->interface->ifindex, iovector, + oi->area->ospf6->fd); + if (len != ntohs(oh->length)) + flog_err(EC_LIB_DEVELOPMENT, + "Could not send entire message"); + } } static uint32_t ospf6_packet_max(struct ospf6_interface *oi) diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c index 9a18680b8b..abbb180d45 100644 --- a/ospf6d/ospf6_network.c +++ b/ospf6d/ospf6_network.c @@ -26,18 +26,19 @@ #include "sockopt.h" #include "privs.h" #include "lib_errors.h" +#include "vrf.h" #include "libospf.h" #include "ospf6_proto.h" #include "ospf6_network.h" #include "ospf6d.h" +#include "ospf6_top.h" -int ospf6_sock; struct in6_addr allspfrouters6; struct in6_addr alldrouters6; /* setsockopt MulticastLoop to off */ -static void ospf6_reset_mcastloop(void) +static void ospf6_reset_mcastloop(int ospf6_sock) { unsigned int off = 0; if (setsockopt(ospf6_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, @@ -47,19 +48,19 @@ static void ospf6_reset_mcastloop(void) safe_strerror(errno)); } -static void ospf6_set_pktinfo(void) +static void ospf6_set_pktinfo(int ospf6_sock) { setsockopt_ipv6_pktinfo(ospf6_sock, 1); } -static void ospf6_set_transport_class(void) +static void ospf6_set_transport_class(int ospf6_sock) { #ifdef IPTOS_PREC_INTERNETCONTROL setsockopt_ipv6_tclass(ospf6_sock, IPTOS_PREC_INTERNETCONTROL); #endif } -static void ospf6_set_checksum(void) +static void ospf6_set_checksum(int ospf6_sock) { int offset = 12; #ifndef DISABLE_IPV6_CHECKSUM @@ -73,21 +74,30 @@ static void ospf6_set_checksum(void) #endif /* DISABLE_IPV6_CHECKSUM */ } -void ospf6_serv_close(void) +void ospf6_serv_close(int *ospf6_sock) { - if (ospf6_sock > 0) { - close(ospf6_sock); - ospf6_sock = -1; + if (*ospf6_sock != -1) { + close(*ospf6_sock); + *ospf6_sock = -1; return; } } /* Make ospf6d's server socket. */ -int ospf6_serv_sock(void) +int ospf6_serv_sock(struct ospf6 *ospf6) { + int ospf6_sock; + + if (ospf6->fd != -1) + return -1; + + if (ospf6->vrf_id == VRF_UNKNOWN) + return -1; + frr_with_privs(&ospf6d_privs) { - ospf6_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP); + ospf6_sock = vrf_socket(AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP, + ospf6->vrf_id, ospf6->name); if (ospf6_sock < 0) { zlog_warn("Network: can't create OSPF6 socket."); return -1; @@ -100,11 +110,12 @@ int ospf6_serv_sock(void) #else ospf6_set_reuseaddr(); #endif /*1*/ - ospf6_reset_mcastloop(); - ospf6_set_pktinfo(); - ospf6_set_transport_class(); - ospf6_set_checksum(); + ospf6_reset_mcastloop(ospf6_sock); + ospf6_set_pktinfo(ospf6_sock); + ospf6_set_transport_class(ospf6_sock); + ospf6_set_checksum(ospf6_sock); + ospf6->fd = ospf6_sock; /* setup global in6_addr, allspf6 and alldr6 for later use */ inet_pton(AF_INET6, ALLSPFROUTERS6, &allspfrouters6); inet_pton(AF_INET6, ALLDROUTERS6, &alldrouters6); @@ -119,11 +130,14 @@ int ospf6_sso(ifindex_t ifindex, struct in6_addr *group, int option) int ret; int bufsize = (8 * 1024 * 1024); + if (ospf6->fd == -1) + return -1; + assert(ifindex); mreq6.ipv6mr_interface = ifindex; memcpy(&mreq6.ipv6mr_multiaddr, group, sizeof(struct in6_addr)); - ret = setsockopt(ospf6_sock, IPPROTO_IPV6, option, &mreq6, + ret = setsockopt(ospf6->fd, IPPROTO_IPV6, option, &mreq6, sizeof(mreq6)); if (ret < 0) { flog_err_sys( @@ -133,8 +147,8 @@ int ospf6_sso(ifindex_t ifindex, struct in6_addr *group, int option) return ret; } - setsockopt_so_sendbuf(ospf6_sock, bufsize); - setsockopt_so_recvbuf(ospf6_sock, bufsize); + setsockopt_so_sendbuf(ospf6->fd, bufsize); + setsockopt_so_recvbuf(ospf6->fd, bufsize); return 0; } @@ -157,7 +171,7 @@ static int iov_totallen(struct iovec *iov) } int ospf6_sendmsg(struct in6_addr *src, struct in6_addr *dst, - ifindex_t *ifindex, struct iovec *message) + ifindex_t *ifindex, struct iovec *message, int ospf6_sock) { int retval; struct msghdr smsghdr; @@ -216,7 +230,7 @@ int ospf6_sendmsg(struct in6_addr *src, struct in6_addr *dst, } int ospf6_recvmsg(struct in6_addr *src, struct in6_addr *dst, - ifindex_t *ifindex, struct iovec *message) + ifindex_t *ifindex, struct iovec *message, int ospf6_sock) { int retval; struct msghdr rmsghdr; diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h index 7fe6e33ff2..eeef0514f3 100644 --- a/ospf6d/ospf6_network.h +++ b/ospf6d/ospf6_network.h @@ -21,17 +21,17 @@ #ifndef OSPF6_NETWORK_H #define OSPF6_NETWORK_H -extern int ospf6_sock; +struct ospf6 *ospf6; extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; -extern int ospf6_serv_sock(void); -extern void ospf6_serv_close(void); +extern int ospf6_serv_sock(struct ospf6 *ospf6); +extern void ospf6_serv_close(int *ospf6_sock); extern int ospf6_sso(ifindex_t ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg(struct in6_addr *, struct in6_addr *, ifindex_t *, - struct iovec *); + struct iovec *, int ospf6_sock); extern int ospf6_recvmsg(struct in6_addr *, struct in6_addr *, ifindex_t *, - struct iovec *); + struct iovec *, int ospf6_sock); #endif /* OSPF6_NETWORK_H */ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 6f23051dc3..49b7e4f142 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -29,6 +29,7 @@ #include "thread.h" #include "command.h" #include "defaults.h" +#include "lib_errors.h" #include "ospf6_proto.h" #include "ospf6_message.h" @@ -41,6 +42,7 @@ #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" +#include "ospf6_network.h" #include "ospf6_flood.h" #include "ospf6_asbr.h" @@ -141,15 +143,21 @@ static void ospf6_top_brouter_hook_remove(struct ospf6_route *route) ospf6_abr_originate_summary(route); } -static struct ospf6 *ospf6_create(vrf_id_t vrf_id) +static struct ospf6 *ospf6_create(const char *name) { struct ospf6 *o; + struct vrf *vrf = NULL; o = XCALLOC(MTYPE_OSPF6_TOP, sizeof(struct ospf6)); + vrf = vrf_lookup_by_name(name); + if (vrf) { + o->vrf_id = vrf->vrf_id; + /* Freed in ospf6_delete */ + o->name = XSTRDUP(MTYPE_OSPF6_TOP, name); + } /* initialize */ monotime(&o->starttime); - o->vrf_id = vrf_id; o->area_list = list_new(); o->area_list->cmp = ospf6_area_cmp; o->lsdb = ospf6_lsdb_create(o); @@ -183,12 +191,28 @@ static struct ospf6 *ospf6_create(vrf_id_t vrf_id) o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; o->distance_table = route_table_init(); + o->fd = -1; QOBJ_REG(o, ospf6); + /* Make ospf protocol socket. */ + ospf6_serv_sock(o); + return o; } +void ospf6_instance_create(const char *name) +{ + ospf6 = ospf6_create(name); + if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES) + SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); + if (ospf6->router_id == 0) + ospf6_router_id_update(); + + thread_add_read(master, ospf6_receive, ospf6, ospf6->fd, + &ospf6->t_ospf6_receive); +} + void ospf6_delete(struct ospf6 *o) { struct listnode *node, *nnode; @@ -217,6 +241,7 @@ void ospf6_delete(struct ospf6 *o) ospf6_distance_reset(o); route_table_finish(o->distance_table); + XFREE(MTYPE_OSPF6_TOP, o->name); XFREE(MTYPE_OSPF6_TOP, o); } @@ -242,6 +267,7 @@ static void ospf6_disable(struct ospf6 *o) THREAD_OFF(o->t_spf_calc); THREAD_OFF(o->t_ase_calc); THREAD_OFF(o->t_distribute_update); + THREAD_OFF(o->t_ospf6_receive); } } @@ -325,14 +351,9 @@ DEFUN_NOSH (router_ospf6, ROUTER_STR OSPF6_STR) { - if (ospf6 == NULL) { - ospf6 = ospf6_create(VRF_DEFAULT); - if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES) - SET_FLAG(ospf6->config_flags, - OSPF6_LOG_ADJACENCY_CHANGES); - if (ospf6->router_id == 0) - ospf6_router_id_update(); - } + if (ospf6 == NULL) + ospf6_instance_create(VRF_DEFAULT_NAME); + /* set current ospf point. */ VTY_PUSH_CONTEXT(OSPF6_NODE, ospf6); @@ -350,6 +371,7 @@ DEFUN (no_router_ospf6, if (ospf6 == NULL) vty_out(vty, "OSPFv3 is not configured\n"); else { + ospf6_serv_close(&ospf6->fd); ospf6_delete(ospf6); ospf6 = NULL; } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 806b4da1cf..a78b05d565 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -40,6 +40,8 @@ struct ospf6 { /* The relevant vrf_id */ vrf_id_t vrf_id; + char *name; /* VRF name */ + /* my router id */ in_addr_t router_id; @@ -92,11 +94,13 @@ struct ospf6 { struct timeval ts_spf_duration; /* Execution time of last SPF */ unsigned int last_spf_reason; /* Last SPF reason */ + int fd; /* Threads */ struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ struct thread *maxage_remover; struct thread *t_distribute_update; /* Distirbute update timer. */ + struct thread *t_ospf6_receive; /* OSPF6 receive timer */ uint32_t ref_bandwidth; @@ -130,5 +134,6 @@ extern void ospf6_delete(struct ospf6 *o); extern void ospf6_router_id_update(void); extern void ospf6_maxage_remove(struct ospf6 *o); +extern void ospf6_instance_create(const char *name); #endif /* OSPF6_TOP_H */ diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 17e33902d9..e904482391 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -1268,9 +1268,8 @@ void ospf6_init(void) &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd); install_element(VIEW_NODE, &show_ipv6_ospf6_database_aggr_router_cmd); - /* Make ospf protocol socket. */ - ospf6_serv_sock(); - thread_add_read(master, ospf6_receive, NULL, ospf6_sock, NULL); + if (ospf6 == NULL) + ospf6_instance_create(VRF_DEFAULT_NAME); } void ospf6_clean(void)