diff options
-rw-r--r-- | accel-pppd/ctrl/pppoe/pppoe.c | 125 | ||||
-rw-r--r-- | accel-pppd/ctrl/pppoe/vpppoe.c | 609 | ||||
-rw-r--r-- | accel-pppd/ctrl/pppoe/vpppoe.h | 23 | ||||
-rw-r--r-- | accel-pppd/include/ap_session.h | 4 | ||||
-rw-r--r-- | accel-pppd/ppp/ppp.c | 37 | ||||
-rw-r--r-- | accel-pppd/session.c | 11 |
6 files changed, 640 insertions, 169 deletions
diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c index 01330c6..25e38a7 100644 --- a/accel-pppd/ctrl/pppoe/pppoe.c +++ b/accel-pppd/ctrl/pppoe/pppoe.c @@ -232,14 +232,16 @@ int pppoe_terminate(struct ap_session *ses, int hard) { struct ppp_t *ppp = container_of(ses, typeof(*ppp), ses); struct pppoe_conn_t *conn = container_of(ppp, typeof(*conn), ppp); - ret = vpppoe_lcp_tun_add_del(ses->vpp_sw_if_index, ses->ifname, 0); - if (ret) - log_warn("VPPPOE: Can't remove VPP lcp TUN pair at terminate: sw_if_index %d name %s\n", ses->vpp_sw_if_index, ses->ifname); - else { - ret = vpppoe_pppoe_session_add_del(conn->addr, &ses->ipv4->peer_addr, conn->sid, 0, NULL); - if (ret) - log_warn("VPPPOE: Can't remove session at terminate: %d %02x.%02x.%02x.%02x.%02x.%02x", conn->sid, - conn->addr[0], conn->addr[1], conn->addr[2], conn->addr[3], conn->addr[4], conn->addr[5]); + if (ppp->is_non_dev_ppp) + { + if (ses->non_dev_ppp_fixup_status == 2) { + vpppoe_async_del_pppoe_interface(conn->addr, &ses->ipv4->peer_addr, conn->sid, ses->vpp_sw_if_index, ses->ifname); + } else if (ses->non_dev_ppp_fixup_status == 1) { + vpppoe_setup_pppoe_interface_ctx_t *callback_ctx = (vpppoe_setup_pppoe_interface_ctx_t *)ses->non_dev_ppp_fixup_priv; + + __sync_or_and_fetch(&callback_ctx->remove_after, 1); + } + } ret = ppp_terminate(ses, hard); @@ -261,58 +263,41 @@ static void ppp_finished(struct ap_session *ses) } } -int pppoe_create_non_dev_ppp_interface(struct ap_session *ses) { +static void pppoe_async_vpppoe_session_created_cb(vpppoe_setup_pppoe_interface_ctx_t *callback_ctx) { + int ret; + struct ifreq ifr; + struct ap_session *ses = (struct ap_session *)callback_ctx->priv; struct ppp_t *ppp = container_of(ses, typeof(*ppp), ses); struct pppoe_conn_t *conn = container_of(ppp, typeof(*conn), ppp); - uint32_t ifindex = -1; - char name[16]; - struct ifreq ifr; - int ret = 0; - if (!ppp->ses.ipv4) { - log_error("VPPPOE: VPP require IPv4 peer addr for session routine"); - return -1; - } - - ret = vpppoe_pppoe_session_add_del(conn->addr, &ses->ipv4->peer_addr, conn->sid, 1, &ifindex); - if (ret) { - log_error("VPPPOE: Can't create VPP session: %d %02x.%02x.%02x.%02x.%02x.%02x", conn->sid, - conn->addr[0], conn->addr[1], conn->addr[2], conn->addr[3], conn->addr[4], conn->addr[5]); - return -1; - } - - snprintf(name, 15, "vppp%d", ifindex); - - ret = vpppoe_lcp_tun_add_del(ifindex, name, 1); - if (ret) { - log_error("VPPPOE: Can't create VPP lcp TUN pair: sw_if_index %d name %s\n", ifindex, name); - goto lsp_vpp_err; - } - - ret = vpppoe_set_feature(ifindex, 0, "ip4-not-enabled", "ip4-unicast"); - if (ret) { - log_error("VPPPOE: Can't set ip4 feature\n"); - goto post_vpp_err; + if (callback_ctx->err) { + ses->non_dev_ppp_fixup_status = 0; + ap_session_terminate(ses, TERM_NAS_ERROR, 0); + _free(callback_ctx); + return; } + + ses->non_dev_ppp_fixup_status = 2; - if (!ppp->ses.ipv6) { - ret = vpppoe_set_feature(ifindex, 0, "ip6-not-enabled", "ip6-unicast"); - if (ret) { - log_error("VPPPOE: Can't set ip6 feature\n"); - goto post_vpp_err; - } + if (__sync_and_and_fetch(&callback_ctx->remove_after, 1)) { + vpppoe_async_del_pppoe_interface(conn->addr, &ses->ipv4->peer_addr, conn->sid, ses->vpp_sw_if_index, ses->ifname); + _free(callback_ctx); + return; } - ses->vpp_sw_if_index = ifindex; + ses->vpp_sw_if_index = callback_ctx->ifindex; - strncpy(ses->ifname, name, IFNAMSIZ - 1); + strncpy(ses->ifname, callback_ctx->ifname, IFNAMSIZ - 1); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ses->ifname, IFNAMSIZ - 1); ret = net->sock_ioctl(SIOCGIFINDEX, &ifr); if (ret) { log_error("VPPPOE: Can't get host ifindex for the interface %s: %s\n", ifr.ifr_name, strerror(errno)); - goto post_vpp_err; + // ap_session_terminate(ses, TERM_NAS_ERROR, 0); + // free(callback_ctx); + return; } + ses->ifindex = ifr.ifr_ifindex; if (ppp->mtu) { @@ -322,7 +307,9 @@ int pppoe_create_non_dev_ppp_interface(struct ap_session *ses) { ret = net->sock_ioctl(SIOCSIFMTU, &ifr); if (ret) { log_error("VPPPOE: Can't setup MTU for interface %s value %d: %s\n", ifr.ifr_name, ifr.ifr_mtu, strerror(errno)); - goto post_vpp_err; + // ap_session_terminate(ses, TERM_NAS_ERROR, 0); + // free(callback_ctx); + return; } } @@ -332,9 +319,39 @@ int pppoe_create_non_dev_ppp_interface(struct ap_session *ses) { log_warn("VPPPOE: Can't setup route %d.%d.%d.%d/32 for interface %d: %s\n", ses->ipv4->peer_addr >> 24 & 0xff, ses->ipv4->peer_addr >> 16 & 0xff, ses->ipv4->peer_addr >> 8 & 0xff, ses->ipv4->peer_addr & 0xff, ses->ifindex, strerror(errno)); - goto post_vpp_err; + // ap_session_terminate(ses, TERM_NAS_ERROR, 0); + // free(callback_ctx); + return; + } + + free(callback_ctx); + ap_session_activate(ses); +} + +int pppoe_create_non_dev_ppp_interface(struct ap_session *ses) { + struct ppp_t *ppp = container_of(ses, typeof(*ppp), ses); + struct pppoe_conn_t *conn = container_of(ppp, typeof(*conn), ppp); + uint32_t ifindex = -1; + char name[16]; + struct ifreq ifr; + int ret = 0; + + if (!ppp->ses.ipv4) { + log_error("VPPPOE: VPP require IPv4 peer addr for session routine"); + return -1; } + ses->non_dev_ppp_fixup_status = 1; + + vpppoe_setup_pppoe_interface_ctx_t *callback_ctx = _malloc(sizeof(*callback_ctx)); + memset(callback_ctx, 0, sizeof(*callback_ctx)); + callback_ctx->tctx = &conn->ctx; + callback_ctx->callback = pppoe_async_vpppoe_session_created_cb; + callback_ctx->priv = ses; + callback_ctx->remove_after = 0; + ses->non_dev_ppp_fixup_priv = callback_ctx; + vpppoe_async_add_pppoe_interface(conn->addr, &ses->ipv4->peer_addr, conn->sid, callback_ctx); + return 0; post_vpp_err: @@ -350,6 +367,7 @@ lsp_vpp_err: } ses->vpp_sw_if_index = -1; + ses->non_dev_ppp_fixup_status = 0; return -1; } @@ -473,10 +491,6 @@ static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const ui conn->ctrl.ifname = serv->ifname; conn->ctrl.mppe = conf_mppe; - if (serv->is_non_dev_ppp) { - conn->ctrl.non_dev_ppp_fixup = pppoe_create_non_dev_ppp_interface; - } - if (ppp_max_payload > ETH_DATA_LEN - 8) conn->ctrl.max_mtu = min(ppp_max_payload, serv->mtu - 8); @@ -556,6 +570,11 @@ static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const ui if (conf_session_timeout) conn->ppp.ses.session_timeout = conf_session_timeout; + if (serv->is_non_dev_ppp) { + conn->ppp.ses.non_dev_ppp_fixup = pppoe_create_non_dev_ppp_interface; + conn->ppp.ses.non_dev_ppp_fixup_status = 0; + } + triton_context_register(&conn->ctx, conn); pthread_mutex_lock(&serv->lock); @@ -2276,7 +2295,7 @@ static void pppoe_init(void) int fd; uint8_t *ptr; - vpppoe_init(); + // vpppoe_init(); ptr = malloc(SID_MAX/8); memset(ptr, 0xff, SID_MAX/8); diff --git a/accel-pppd/ctrl/pppoe/vpppoe.c b/accel-pppd/ctrl/pppoe/vpppoe.c index 4dea5cd..c5fdcf7 100644 --- a/accel-pppd/ctrl/pppoe/vpppoe.c +++ b/accel-pppd/ctrl/pppoe/vpppoe.c @@ -6,6 +6,13 @@ #include <vapi/feature.api.vapi.h> #include <linux/if_ether.h> +#include <pthread.h> + +#include <memory.h> +#include <stdio.h> + +#include "events.h" +#include "triton.h" #include "vpppoe.h" @@ -15,172 +22,590 @@ DEFINE_VAPI_MSG_IDS_PPPOE_API_JSON DEFINE_VAPI_MSG_IDS_LCP_API_JSON DEFINE_VAPI_MSG_IDS_FEATURE_API_JSON -static struct vpp_connect_t { - vapi_ctx_t vapi; - int rfcounter; +static uint32_t sc_fallback_timer = 1000; + +/* rcbc - Reply CallBack Counter. Retry postponed calls if waiting less then sc_fallback_at_rcbc at curent time */ +static int sc_fallback_at_rcbc = 1024; +static int sc_vpp_queue_size = 2048; + +static int sc_teardown_on_max_queue = 512; + +static int sc_non_lcp_mode = 0; + +static struct vpp_connect_t +{ + vapi_ctx_t vapi; + int rfcounter; + + int rcbc; + + pthread_mutex_t lock_vpp; + + struct triton_context_t tctx; + struct triton_md_handler_t vapi_read_hnd; + + struct triton_timer_t timer; + + /* retry fallback lists */ + uint32_t retry_del_count; + struct list_head retry_del_list; } vpp_connect; const char vpp_app_name[] = "accel-vpppoe"; +static int vpppoe_read_events(struct triton_md_handler_t *h); +static void vpppoe_disconnect_from_vpp(); +static void vpppoe_timer(struct triton_timer_t *t); + +static void vpppoe_fallback_allocate_and_add_postponed_pppoe_del(uint8_t *client_mac, in_addr_t *client_ip, uint16_t session_id); + static void vpppoe_connect_to_vpp() { - vapi_error_e verr = vapi_ctx_alloc(&vpp_connect.vapi); + int fd = -1; + vapi_error_e verr = vapi_ctx_alloc(&vpp_connect.vapi); - if (verr != VAPI_OK) { - vpp_connect.vapi = NULL; + if (verr != VAPI_OK) + { + vpp_connect.vapi = NULL; return; } - verr = vapi_connect_ex(vpp_connect.vapi, vpp_app_name, NULL, 32, 32, VAPI_MODE_BLOCKING, true, true); + verr = vapi_connect_ex(vpp_connect.vapi, vpp_app_name, NULL, sc_vpp_queue_size, sc_vpp_queue_size, VAPI_MODE_NONBLOCKING, true, true); + if (verr != VAPI_OK) + { + vapi_ctx_free(vpp_connect.vapi); + vpp_connect.vapi = NULL; + return; + } - if (verr != VAPI_OK) { - vapi_ctx_free(vpp_connect.vapi); - vpp_connect.vapi = NULL; + verr = vapi_get_fd(vpp_connect.vapi, &fd); + if (verr != VAPI_OK) + { + vapi_disconnect_from_vpp(vpp_connect.vapi); + vapi_ctx_free(vpp_connect.vapi); + vpp_connect.vapi = NULL; + return; } + + memset(&vpp_connect.tctx, 0, sizeof(vpp_connect.tctx)); + memset(&vpp_connect.vapi_read_hnd, 0, sizeof(vpp_connect.vapi_read_hnd)); + + vpp_connect.vapi_read_hnd.fd = fd; + vpp_connect.vapi_read_hnd.read = vpppoe_read_events; + + // TODO: add options for triton ctx aka close and free + + vpp_connect.timer.expire = vpppoe_timer; + vpp_connect.timer.period = sc_fallback_timer; + + // TODO: add checks + triton_context_register(&vpp_connect.tctx, NULL); + triton_md_register_handler(&vpp_connect.tctx, &vpp_connect.vapi_read_hnd); + triton_md_enable_handler(&vpp_connect.vapi_read_hnd, MD_MODE_READ); + triton_timer_add(&vpp_connect.tctx, &vpp_connect.timer, 0); + triton_context_wakeup(&vpp_connect.tctx); } -static void vpppoe_disconnect_from_vpp() +void vpppoe_disconnect_from_vpp() { - vapi_disconnect(vpp_connect.vapi); - vapi_ctx_free(vpp_connect.vapi); - vpp_connect.vapi = NULL; -} + triton_timer_del(&vpp_connect.timer); + triton_md_unregister_handler(&vpp_connect.vapi_read_hnd, 0); + triton_context_unregister(&vpp_connect.tctx); -void vpppoe_init() { + vapi_disconnect(vpp_connect.vapi); + vapi_ctx_free(vpp_connect.vapi); vpp_connect.vapi = NULL; - vpp_connect.rfcounter = 0; - - memset(&vpp_connect, 0, sizeof(vpp_connect)); } void vpppoe_get() { int rfc = __sync_fetch_and_add(&vpp_connect.rfcounter, 1); - if (!rfc) - vpppoe_connect_to_vpp(); + if (!rfc) + vpppoe_connect_to_vpp(); } void vpppoe_put() { int rfc = __sync_sub_and_fetch(&vpp_connect.rfcounter, 1); - if (!rfc) - vpppoe_disconnect_from_vpp(); + if (!rfc) + vpppoe_disconnect_from_vpp(); +} + +static vapi_error_e vpppoe_set_feature_callback(struct vapi_ctx_s *ctx, + void *callback_ctx, + vapi_error_e rv, + bool is_last, + vapi_payload_feature_enable_disable_reply *reply) +{ + if (is_last) + vpp_connect.rcbc -= 1; + return VAPI_OK; } -static vapi_error_e vpppoe_session_add_reply_callback(struct vapi_ctx_s *ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_pppoe_add_del_session_reply *reply) +int vpppoe_set_feature(uint32_t ifindex, int is_enabled, const char *feature, const char *arc) { - if (callback_ctx != NULL && reply != NULL) { - uint32_t *sw = (uint32_t *)(callback_ctx); - *sw = reply->sw_if_index; - } + vapi_error_e err; + vapi_msg_feature_enable_disable *req = vapi_alloc_feature_enable_disable(vpp_connect.vapi); + if (req == NULL) + return -1; - return VAPI_OK; + strncpy((char *)req->payload.feature_name, feature, 63); + strncpy((char *)req->payload.arc_name, arc, 63); + req->payload.sw_if_index = ifindex; + req->payload.enable = is_enabled; + + pthread_mutex_lock(&vpp_connect.lock_vpp); + vpp_connect.rcbc += 1; + err = vapi_feature_enable_disable(vpp_connect.vapi, req, vpppoe_set_feature_callback, NULL); + pthread_mutex_unlock(&vpp_connect.lock_vpp); + + return err; } -int vpppoe_pppoe_session_add_del(uint8_t *client_mac, in_addr_t *client_ip, uint16_t session_id, int is_add, uint32_t *out_ifindex) +typedef struct vpppoe_add_pppoe_interface_cb_ctx_t { - vapi_msg_pppoe_add_del_session *req = vapi_alloc_pppoe_add_del_session(vpp_connect.vapi); + uint8_t client_mac[ETH_ALEN]; + in_addr_t client_ip; + uint16_t session_id; + vpppoe_setup_pppoe_interface_ctx_t *callback_ctx; +} vpppoe_add_pppoe_interface_cb_ctx_t; + +int vpppoe_async_add_pppoe_interface_with_callback(vpppoe_add_pppoe_interface_cb_ctx_t *vppoe_callback_ctx); +static void vpppoe_a_add_lcp_pair_triton(vpppoe_add_pppoe_interface_cb_ctx_t *vpppoe_callback_ctx); + +static void vpppoe_a_setup_features_triton(vpppoe_setup_pppoe_interface_ctx_t *vpppoe_callback_ctx) { + vpppoe_set_feature(vpppoe_callback_ctx->ifindex, 0, "ip4-not-enabled", "ip4-unicast"); + vpppoe_set_feature(vpppoe_callback_ctx->ifindex, 0, "ip6-not-enabled", "ip6-unicast"); + triton_context_call(vpppoe_callback_ctx->tctx, (triton_event_func)vpppoe_callback_ctx->callback, vpppoe_callback_ctx); +} + +static vapi_error_e vpppoe_a_lcp_callback(struct vapi_ctx_s *ctx, + void *callback_ctx, + vapi_error_e rv, + bool is_last, + vapi_payload_lcp_itf_pair_add_del_reply *reply) +{ + + if (is_last) + vpp_connect.rcbc -= 1; + + vpppoe_add_pppoe_interface_cb_ctx_t *vpppoe_callback_ctx = (vpppoe_add_pppoe_interface_cb_ctx_t *)callback_ctx; + + if (callback_ctx != NULL && reply != NULL && rv == VAPI_OK) + { + triton_context_call(&vpp_connect.tctx, (triton_event_func)vpppoe_a_setup_features_triton, vpppoe_callback_ctx->callback_ctx); + free(vpppoe_callback_ctx); + } else { + fprintf(stderr, "\e[1;31m --| %s unexpected issue ctx %p reply %p rv %d rcbc %d\e[0m\n", __FUNCTION__, callback_ctx, reply, rv, vpp_connect.rcbc); + if (vpppoe_callback_ctx != NULL) { + + fprintf(stderr, "\e[1;31m --| %s ISSUE during lcp creation sid %d rcbc %d\e[0m\n", __FUNCTION__, vpppoe_callback_ctx->session_id, vpp_connect.rcbc); + + vpppoe_fallback_allocate_and_add_postponed_pppoe_del(vpppoe_callback_ctx->client_mac, &vpppoe_callback_ctx->client_ip, vpppoe_callback_ctx->session_id); + + vpppoe_callback_ctx->callback_ctx->err = rv; + triton_context_call(vpppoe_callback_ctx->callback_ctx->tctx, (triton_event_func)vpppoe_callback_ctx->callback_ctx->callback, vpppoe_callback_ctx->callback_ctx); + free(vpppoe_callback_ctx); + } + } + return rv; +} + +void vpppoe_a_add_lcp_pair_triton(vpppoe_add_pppoe_interface_cb_ctx_t *vpppoe_callback_ctx) { + vapi_error_e err; + vapi_msg_lcp_itf_pair_add_del *req = vapi_alloc_lcp_itf_pair_add_del(vpp_connect.vapi); + + // TODO check logic if (req == NULL) + { + fprintf(stderr, "\e[1;31m --| %s can't allocate lcp add request ifindex %d rcbc %d\e[0m\n", __FUNCTION__, vpppoe_callback_ctx->callback_ctx->ifindex, vpp_connect.rcbc); + return; + } + + snprintf((char *)req->payload.host_if_name, 15, "vppp%d", vpppoe_callback_ctx->callback_ctx->ifindex); + strncpy(vpppoe_callback_ctx->callback_ctx->ifname, (char *)req->payload.host_if_name, 15); + // strncpy((char *)req->payload.host_if_name, host_if_name, 15); + req->payload.sw_if_index = vpppoe_callback_ctx->callback_ctx->ifindex; + req->payload.host_if_type = LCP_API_ITF_HOST_TUN; + req->payload.is_add = 1; + + pthread_mutex_lock(&vpp_connect.lock_vpp); + vpp_connect.rcbc += 1; + err = vapi_lcp_itf_pair_add_del(vpp_connect.vapi, req, vpppoe_a_lcp_callback, vpppoe_callback_ctx); + pthread_mutex_unlock(&vpp_connect.lock_vpp); + + if (err != VAPI_OK) + { + if (vpppoe_callback_ctx != NULL) + { + fprintf(stderr, "\e[1;31m --| %s can't send lcp pair creation request sid %d rcbc %d\e[0m\n", __FUNCTION__, vpppoe_callback_ctx->session_id, vpp_connect.rcbc); + + vpppoe_fallback_allocate_and_add_postponed_pppoe_del(vpppoe_callback_ctx->client_mac, &vpppoe_callback_ctx->client_ip, vpppoe_callback_ctx->session_id); + + vpppoe_callback_ctx->callback_ctx->err = err; + triton_context_call(vpppoe_callback_ctx->callback_ctx->tctx, (triton_event_func)vpppoe_callback_ctx->callback_ctx->callback, vpppoe_callback_ctx->callback_ctx); + free(vpppoe_callback_ctx); + } + } +} + +static vapi_error_e vpppoe_a_session_add_reply_callback(struct vapi_ctx_s *ctx, + void *callback_ctx, + vapi_error_e rv, + bool is_last, + vapi_payload_pppoe_add_del_session_reply *reply) +{ + + if (is_last) + vpp_connect.rcbc -= 1; + + vpppoe_add_pppoe_interface_cb_ctx_t *vpppoe_callback_ctx = (vpppoe_add_pppoe_interface_cb_ctx_t *)callback_ctx; + if (callback_ctx != NULL && reply != NULL && rv == VAPI_OK) + { + vpppoe_callback_ctx->callback_ctx->ifindex = reply->sw_if_index; + if (sc_non_lcp_mode) { + triton_context_call(&vpp_connect.tctx, (triton_event_func)vpppoe_a_setup_features_triton, vpppoe_callback_ctx->callback_ctx); + free(vpppoe_callback_ctx); + } else { + triton_context_call(&vpp_connect.tctx, (triton_event_func)vpppoe_a_add_lcp_pair_triton, vpppoe_callback_ctx); + } + fprintf(stderr, "\e[1;32m --| %s add pppoe session ifindex %d rcbc %d \e[0m\n", __FUNCTION__, vpppoe_callback_ctx->callback_ctx->ifindex, vpp_connect.rcbc); + } else { + fprintf(stderr, "\e[1;31m --| %s unexpected issue ctx %p reply %p rv %d rcbc %d\e[0m\n", __FUNCTION__, callback_ctx, reply, rv, vpp_connect.rcbc); + + if (vpppoe_callback_ctx != NULL) { + + vpppoe_callback_ctx->callback_ctx->err = rv; + triton_context_call(vpppoe_callback_ctx->callback_ctx->tctx, (triton_event_func)vpppoe_callback_ctx->callback_ctx->callback, vpppoe_callback_ctx->callback_ctx); + free(vpppoe_callback_ctx); + } + } + + return rv; +} + +int vpppoe_async_add_pppoe_interface_with_callback(vpppoe_add_pppoe_interface_cb_ctx_t *vppoe_callback_ctx) { + vapi_error_e err; + + vapi_msg_pppoe_add_del_session *req = vapi_alloc_pppoe_add_del_session(vpp_connect.vapi); + if (req == NULL) { + fprintf(stderr, "\e[1;31m --| %s can't allocate pppoe add request session %d rcbc %d\e[0m\n", __FUNCTION__, vppoe_callback_ctx->session_id, vpp_connect.rcbc); + return -1; + } + + vppoe_callback_ctx->callback_ctx->err = 0; + vppoe_callback_ctx->callback_ctx->ifindex = 0; req->payload.client_ip.af = ADDRESS_IP4; - memcpy(req->payload.client_ip.un.ip4, client_ip, sizeof(*client_ip)); - memcpy(req->payload.client_mac, client_mac, ETH_ALEN); + memcpy(req->payload.client_ip.un.ip4, &vppoe_callback_ctx->client_ip, sizeof(vppoe_callback_ctx->client_ip)); + memcpy(req->payload.client_mac, vppoe_callback_ctx->client_mac, ETH_ALEN); - req->payload.is_add = is_add; - req->payload.session_id = session_id; + req->payload.is_add = 1; + req->payload.session_id = vppoe_callback_ctx->session_id; req->payload.disable_fib = 1; - return vapi_pppoe_add_del_session(vpp_connect.vapi, req, vpppoe_session_add_reply_callback, out_ifindex); + pthread_mutex_lock(&vpp_connect.lock_vpp); + vpp_connect.rcbc += 1; + err = vapi_pppoe_add_del_session(vpp_connect.vapi, req, vpppoe_a_session_add_reply_callback, vppoe_callback_ctx); + pthread_mutex_unlock(&vpp_connect.lock_vpp); + + if (err != VAPI_OK) { + if (vppoe_callback_ctx != NULL) { + fprintf(stderr, "\e[1;31m --| %s can't send pppoe creation request sid %d rcbc %d\e[0m\n", __FUNCTION__, vppoe_callback_ctx->session_id, vpp_connect.rcbc); + vppoe_callback_ctx->callback_ctx->err = err; + triton_context_call(vppoe_callback_ctx->callback_ctx->tctx, (triton_event_func)vppoe_callback_ctx->callback_ctx->callback, vppoe_callback_ctx->callback_ctx); + free(vppoe_callback_ctx); + } + } + + return err; } -typedef struct { +int vpppoe_async_add_pppoe_interface(uint8_t *client_mac, in_addr_t *client_ip, uint16_t session_id, vpppoe_setup_pppoe_interface_ctx_t *callback_ctx) +{ + if (vpp_connect.rcbc >= sc_teardown_on_max_queue) { + fprintf(stderr, "\e[1;31m --| %s TOO much request sid %d rcbc %d\e[0m\n", __FUNCTION__, session_id, vpp_connect.rcbc); + callback_ctx->err = -100; + triton_context_call(callback_ctx->tctx, (triton_event_func)callback_ctx->callback, callback_ctx); + return -100; + } + + vpppoe_add_pppoe_interface_cb_ctx_t *vpppoe_callback_ctx = malloc(sizeof(*vpppoe_callback_ctx)); + memset(vpppoe_callback_ctx, 0, sizeof(*vpppoe_callback_ctx)); + + memcpy(&vpppoe_callback_ctx->client_ip, client_ip, sizeof(*client_ip)); + memcpy(vpppoe_callback_ctx->client_mac, client_mac, ETH_ALEN); + vpppoe_callback_ctx->session_id = session_id; + vpppoe_callback_ctx->callback_ctx = callback_ctx; + + return vpppoe_async_add_pppoe_interface_with_callback(vpppoe_callback_ctx); +} + +typedef struct vpppoe_del_pppoe_interface_cb_ctx_t +{ + uint8_t mac[ETH_ALEN]; + in_addr_t client_ip; + uint16_t session_id; uint32_t ifindex; - char *name; - size_t len; -} vpppoe_ifname_by_ifindex_t; - -static vapi_error_e vpppoe_ifname_by_ifindex_reply_callback(struct vapi_ctx_s *ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_sw_interface_details *reply) -{ - if (reply && callback_ctx != NULL) { - vpppoe_ifname_by_ifindex_t *ifname = (vpppoe_ifname_by_ifindex_t *)callback_ctx; - if (ifname->ifindex == reply->sw_if_index) { - size_t len = ifname->len > 63 ? 63 : ifname->len; - strncpy(ifname->name, (const char *)reply->interface_name, len); + char ifname[16]; + + /* retry fallback */ + uint32_t retrys; + struct list_head entry; + uint32_t retry_at; /* 0 - from lcp delete routine, 1 - from pppoe session delete routine */ +} vpppoe_del_pppoe_interface_cb_ctx_t; + + +static void vpppoe_async_del_pppoe_interface_with_callback(vpppoe_del_pppoe_interface_cb_ctx_t *callback_ctx); +static void vpppoe_a_del_session_triton(vpppoe_del_pppoe_interface_cb_ctx_t *vpppoe_callback_ctx); + +static void vpppoe_retry_del_later(vpppoe_del_pppoe_interface_cb_ctx_t *ctx) { + ctx->retrys += 1; + vpp_connect.retry_del_count += 1; + list_add_tail(&ctx->entry, &vpp_connect.retry_del_list); +} + +void vpppoe_fallback_allocate_and_add_postponed_pppoe_del(uint8_t *client_mac, in_addr_t *client_ip, uint16_t session_id) { + + vpppoe_del_pppoe_interface_cb_ctx_t *callback_ctx = malloc(sizeof(*callback_ctx)); + memset(callback_ctx, 0, sizeof(*callback_ctx)); + memcpy(&callback_ctx->mac, client_mac, ETH_ALEN); + memcpy(&callback_ctx->client_ip, client_ip, sizeof(*client_ip)); + callback_ctx->session_id = session_id; + + callback_ctx->retry_at = 1; + vpppoe_retry_del_later(callback_ctx); +} + +static void vpppoe_launch_del_retrys(uint32_t count) { + if (vpp_connect.retry_del_count) { + + uint32_t i = 0; + struct list_head *pos, *n; + vpppoe_del_pppoe_interface_cb_ctx_t *callback_ctx; + + list_for_each_safe(pos, n, &vpp_connect.retry_del_list) { + callback_ctx = list_entry(pos, typeof(*callback_ctx), entry); + + vpp_connect.retry_del_count -= 1; + list_del(&callback_ctx->entry); + + fprintf(stderr, "\033[104m --| %s RETRY DEL %d ifname %16s rcbc %d retry %d\e[0m\n", __FUNCTION__, callback_ctx->ifindex, callback_ctx->ifname, vpp_connect.rcbc, vpp_connect.retry_del_count); + + if (callback_ctx->retry_at == 0) + vpppoe_async_del_pppoe_interface_with_callback(callback_ctx); + else + vpppoe_a_del_session_triton(callback_ctx); + + ++i; + if (i > count) { + break; + } } } +} + +static vapi_error_e vpppoe_a_del_session_add_reply_callback(struct vapi_ctx_s *ctx, + void *callback_ctx, + vapi_error_e rv, + bool is_last, + vapi_payload_pppoe_add_del_session_reply *reply) +{ + if (is_last) + vpp_connect.rcbc -= 1; + + vpppoe_del_pppoe_interface_cb_ctx_t *vpppoe_callback_ctx = (vpppoe_del_pppoe_interface_cb_ctx_t *)callback_ctx; + if (callback_ctx && rv == VAPI_OK) { + fprintf(stderr, "\e[1;33m --| %s del pppoe %p %p %d ifindex %d ifname %s rcbc %d \e[0m\n", __FUNCTION__, callback_ctx, reply, rv, vpppoe_callback_ctx->ifindex, vpppoe_callback_ctx->ifname, vpp_connect.rcbc); + free(vpppoe_callback_ctx); + + } else { + fprintf(stderr, "\e[1;31m --| %s some issue in pppoe del - adding to the retry list - responce %d ifindex %d ifname %16s rcbc %d retrys %d\e[0m\n", __FUNCTION__, rv, vpppoe_callback_ctx->ifindex, vpppoe_callback_ctx->ifname, vpp_connect.rcbc, vpp_connect.retry_del_count); + vpppoe_callback_ctx->retry_at = 1; + vpppoe_retry_del_later(vpppoe_callback_ctx); + + } return VAPI_OK; } -int vpppoe_get_sw_ifname_by_index(uint32_t sw_ifindex, char *ifname, size_t len) -{ - vpppoe_ifname_by_ifindex_t ctx; +void vpppoe_a_del_session_triton(vpppoe_del_pppoe_interface_cb_ctx_t *vpppoe_callback_ctx) { - ctx.ifindex = sw_ifindex; - ctx.name = ifname; - ctx.len = len; + vapi_error_e err; - vapi_msg_sw_interface_dump *req = vapi_alloc_sw_interface_dump(vpp_connect.vapi, 0); - if (req == NULL) - return -1; + if (vpp_connect.rcbc >= sc_teardown_on_max_queue) { + fprintf(stderr, "\e[1;31m --| %s TOO much DEL LCP request - add to postpone list sid %d ifindex %d rcbc %d\e[0m\n", __FUNCTION__, vpppoe_callback_ctx->session_id, vpppoe_callback_ctx->ifindex, vpp_connect.rcbc); + vpppoe_callback_ctx->retry_at = 1; + vpppoe_retry_del_later(vpppoe_callback_ctx); + return; + } - req->payload.sw_if_index = sw_ifindex; + vapi_msg_pppoe_add_del_session *req = vapi_alloc_pppoe_add_del_session(vpp_connect.vapi); + if (req == NULL) { + fprintf(stderr, "\e[1;31m --| %s can't allocate pppoe delete request ifindex %d ifname %16s rcbc %d\e[0m\n", __FUNCTION__, vpppoe_callback_ctx->ifindex, vpppoe_callback_ctx->ifname, vpp_connect.rcbc); + return; + } - return vapi_sw_interface_dump(vpp_connect.vapi, req, vpppoe_ifname_by_ifindex_reply_callback, &ctx); -} + req->payload.client_ip.af = ADDRESS_IP4; + memcpy(req->payload.client_ip.un.ip4, &vpppoe_callback_ctx->client_ip, sizeof(vpppoe_callback_ctx->client_ip)); + memcpy(req->payload.client_mac, &vpppoe_callback_ctx->mac, ETH_ALEN); + req->payload.is_add = 0; + req->payload.session_id = vpppoe_callback_ctx->session_id; + // req->payload.disable_fib = 1; -static vapi_error_e vpppoe_lsc_callback(struct vapi_ctx_s *ctx, + + pthread_mutex_lock(&vpp_connect.lock_vpp); + vpp_connect.rcbc += 1; + err = vapi_pppoe_add_del_session(vpp_connect.vapi, req, vpppoe_a_del_session_add_reply_callback, vpppoe_callback_ctx); + pthread_mutex_unlock(&vpp_connect.lock_vpp); + + if (err != VAPI_OK) { + fprintf(stderr, "\e[1;31m --| %s cant SEND pppoe del - adding to the retry list - responce %d ifindex %d ifname %16s rcbc %d retrys %d\e[0m\n", __FUNCTION__, err, vpppoe_callback_ctx->ifindex, vpppoe_callback_ctx->ifname, vpp_connect.rcbc, vpp_connect.retry_del_count); + vpppoe_callback_ctx->retry_at = 1; + vpppoe_retry_del_later(vpppoe_callback_ctx); + } +} + +static vapi_error_e vpppoe_a_del_lcp_callback(struct vapi_ctx_s *ctx, void *callback_ctx, vapi_error_e rv, bool is_last, vapi_payload_lcp_itf_pair_add_del_reply *reply) { + + if (is_last) + vpp_connect.rcbc -= 1; + + vpppoe_del_pppoe_interface_cb_ctx_t *vpppoe_callback_ctx = (vpppoe_del_pppoe_interface_cb_ctx_t *)callback_ctx; + + if (callback_ctx != NULL && rv == VAPI_OK) + { + triton_context_call(&vpp_connect.tctx, (triton_event_func)vpppoe_a_del_session_triton, vpppoe_callback_ctx); + + } else { + fprintf(stderr, "\e[1;31m --| %s unexpected issue ctx %p reply %p rv %d rcbc %d\e[0m\n", __FUNCTION__, callback_ctx, reply, rv, vpp_connect.rcbc); + if (vpppoe_callback_ctx != NULL) { + fprintf(stderr, "\e[1;31m --| %s some issue in lcp del - adding to the retry list - responce %d ifindex %d ifname %16s rcbc %d retrys %d\e[0m\n", __FUNCTION__, rv, vpppoe_callback_ctx->ifindex, vpppoe_callback_ctx->ifname, vpp_connect.rcbc, vpp_connect.retry_del_count); + vpppoe_callback_ctx->retry_at = 0; + vpppoe_retry_del_later(vpppoe_callback_ctx); + + } + } + return VAPI_OK; } -int vpppoe_lcp_tun_add_del(uint32_t ifindex, const char *host_if_name, int is_add) -{ - vapi_msg_lcp_itf_pair_add_del* req = vapi_alloc_lcp_itf_pair_add_del(vpp_connect.vapi); +void vpppoe_async_del_pppoe_interface_with_callback(vpppoe_del_pppoe_interface_cb_ctx_t *callback_ctx) { + + vapi_error_e err; + + if (vpp_connect.rcbc >= sc_teardown_on_max_queue) { + fprintf(stderr, "\e[1;31m --| %s TOO much DEL request - add to postpone list sid %d ifindex %d rcbc %d\e[0m\n", __FUNCTION__, callback_ctx->session_id, callback_ctx->ifindex, vpp_connect.rcbc); + callback_ctx->retry_at = 0; + vpppoe_retry_del_later(callback_ctx); + return; + } + + vapi_msg_lcp_itf_pair_add_del *req = vapi_alloc_lcp_itf_pair_add_del(vpp_connect.vapi); + if (req == NULL) - return -1; + { + fprintf(stderr, "\e[1;31m --| %s can't allocate lcp delete request ifindex %d ifname %16s rcbc %d\e[0m\n", __FUNCTION__, + callback_ctx->ifindex, callback_ctx->ifname, vpp_connect.rcbc); + return; + } - strncpy((char *)req->payload.host_if_name, host_if_name, 15); - req->payload.sw_if_index = ifindex; + strncpy((char *)req->payload.host_if_name, callback_ctx->ifname, 15); + req->payload.sw_if_index = callback_ctx->ifindex; req->payload.host_if_type = LCP_API_ITF_HOST_TUN; - req->payload.is_add = is_add; + req->payload.is_add = 0; + + + pthread_mutex_lock(&vpp_connect.lock_vpp); + vpp_connect.rcbc += 1; + err = vapi_lcp_itf_pair_add_del(vpp_connect.vapi, req, vpppoe_a_del_lcp_callback, callback_ctx); + pthread_mutex_unlock(&vpp_connect.lock_vpp); + + if (err != VAPI_OK) { + fprintf(stderr, "\e[1;31m --| %s cant SEND lcp del - adding to the retry list - responce %d ifindex %d ifname %16s rcbc %d retrys %d\e[0m\n", __FUNCTION__, err, callback_ctx->ifindex, callback_ctx->ifname, vpp_connect.rcbc, vpp_connect.retry_del_count); + callback_ctx->retry_at = 0; + vpppoe_retry_del_later(callback_ctx); + } +} + +void vpppoe_async_del_pppoe_interface(uint8_t *client_mac, in_addr_t *client_ip, uint16_t session_id, uint32_t ifindex, char *ifname) { + vpppoe_del_pppoe_interface_cb_ctx_t *callback_ctx = malloc(sizeof(*callback_ctx)); + memset(callback_ctx, 0, sizeof(*callback_ctx)); + memcpy(&callback_ctx->mac, client_mac, ETH_ALEN); + memcpy(&callback_ctx->client_ip, client_ip, sizeof(*client_ip)); + callback_ctx->session_id = session_id; - return vapi_lcp_itf_pair_add_del(vpp_connect.vapi, req, vpppoe_lsc_callback, NULL); + callback_ctx->ifindex = ifindex; + strncpy((char *)&callback_ctx->ifname, ifname, 15); + + if (sc_non_lcp_mode) { + vpppoe_a_del_session_triton(callback_ctx); + } else { + vpppoe_async_del_pppoe_interface_with_callback(callback_ctx); + } } -static vapi_error_e vpppoe_set_feature_callback(struct vapi_ctx_s *ctx, - void *callback_ctx, - vapi_error_e rv, - bool is_last, - vapi_payload_feature_enable_disable_reply *reply) + +/* NOTE DIRTY HACKS ALL AROUND! */ +int vpppoe_read_events(struct triton_md_handler_t *h) { - return VAPI_OK; + pthread_mutex_lock(&vpp_connect.lock_vpp); + vapi_dispatch(vpp_connect.vapi); + pthread_mutex_unlock(&vpp_connect.lock_vpp); + + return 0; } -int vpppoe_set_feature(uint32_t ifindex, int is_enabled, const char *feature, const char *arc) +void vpppoe_timer(struct triton_timer_t *t) { + + if (vpp_connect.rcbc < sc_fallback_at_rcbc) { + vpppoe_launch_del_retrys(sc_teardown_on_max_queue); + } + /* HACK */ + vpppoe_read_events(NULL); +} + +static void vpppoe_load_config(void) { - vapi_msg_feature_enable_disable* req = vapi_alloc_feature_enable_disable(vpp_connect.vapi); - if (req == NULL) - return -1; + char *opt; + + opt = conf_get_opt("vpp", "queue_size"); + if (opt) + sc_vpp_queue_size = atoi(opt); + + opt = conf_get_opt("vpp", "fallback_timer"); + if (opt) + sc_fallback_timer = atoi(opt); + + opt = conf_get_opt("vpp", "teardown_at_max_requests"); + if (opt) + sc_fallback_at_rcbc = atoi(opt); + + opt = conf_get_opt("vpp", "fallback_requests"); + if (opt) + sc_teardown_on_max_queue = atoi(opt); + + opt = conf_get_opt("vpp", "non_lcp_mode"); + if (opt) + sc_non_lcp_mode = atoi(opt); +} - strncpy((char *)req->payload.feature_name, feature, 63); - strncpy((char *)req->payload.arc_name, arc, 63); - req->payload.sw_if_index = ifindex; - req->payload.enable = is_enabled; +static void vpppoe_init() +{ + memset(&vpp_connect, 0, sizeof(vpp_connect)); + INIT_LIST_HEAD(&vpp_connect.retry_del_list); + pthread_mutex_init(&vpp_connect.lock_vpp, NULL); + + vpppoe_load_config(); - return vapi_feature_enable_disable(vpp_connect.vapi, req, vpppoe_set_feature_callback, NULL); + triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)vpppoe_load_config); } + +DEFINE_INIT(20, vpppoe_init);
\ No newline at end of file diff --git a/accel-pppd/ctrl/pppoe/vpppoe.h b/accel-pppd/ctrl/pppoe/vpppoe.h index 5b41070..d56bd74 100644 --- a/accel-pppd/ctrl/pppoe/vpppoe.h +++ b/accel-pppd/ctrl/pppoe/vpppoe.h @@ -1,13 +1,26 @@ #ifndef VPPPOE_H #define VPPPOE_H -void vpppoe_init(); void vpppoe_get(); void vpppoe_put(); -int vpppoe_pppoe_session_add_del(uint8_t *client_mac, in_addr_t *client_ip, uint16_t session_id, int is_add, uint32_t *out_ifindex); -int vpppoe_get_sw_ifname_by_index(uint32_t sw_ifindex, char *ifname, size_t len); -int vpppoe_lcp_tun_add_del(uint32_t ifindex, const char *host_if_name, int is_add); -int vpppoe_set_feature(uint32_t ifindex, int is_enabled, const char *feature, const char *arc); +struct triton_context_t; + +typedef struct vpppoe_setup_pppoe_interface_ctx_t +{ + struct triton_context_t *tctx; + void (*callback)(struct vpppoe_setup_pppoe_interface_ctx_t *ctx); + void *priv; + + int remove_after; + + /* Output values */ + int err; /* 0 - OK */ + uint32_t ifindex; + char ifname[16]; +} vpppoe_setup_pppoe_interface_ctx_t; + +int vpppoe_async_add_pppoe_interface(uint8_t *client_mac, in_addr_t *client_ip, uint16_t session_id, vpppoe_setup_pppoe_interface_ctx_t *callback_ctx); +void vpppoe_async_del_pppoe_interface(uint8_t *client_mac, in_addr_t *client_ip, uint16_t session_id, uint32_t ifindex, char *ifname); #endif /* VPPPOE_H */
\ No newline at end of file diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h index c032c3f..61da292 100644 --- a/accel-pppd/include/ap_session.h +++ b/accel-pppd/include/ap_session.h @@ -58,7 +58,6 @@ struct ap_ctrl { void (*started)(struct ap_session*); void (*finished)(struct ap_session *); int (*terminate)(struct ap_session *, int hard); - int (*non_dev_ppp_fixup)(struct ap_session*); }; struct ap_private @@ -122,6 +121,9 @@ struct ap_session uint64_t acct_tx_bytes_i; int acct_start; + int (*non_dev_ppp_fixup)(struct ap_session*); + int non_dev_ppp_fixup_status; /* 0 nondone, 1 processing, 2 done */ + void *non_dev_ppp_fixup_priv; uint32_t vpp_sw_if_index; }; diff --git a/accel-pppd/ppp/ppp.c b/accel-pppd/ppp/ppp.c index 1ee612b..8fda7c7 100644 --- a/accel-pppd/ppp/ppp.c +++ b/accel-pppd/ppp/ppp.c @@ -143,8 +143,12 @@ int __export establish_ppp(struct ppp_t *ppp) return 0; exit_close_chan: - if (!ppp->is_non_dev_ppp) + if (!ppp->is_non_dev_ppp) { close(ppp->chan_fd); + } + + ppp->chan_fd = -1; + ppp->chan_hnd.fd = -1; return -1; } @@ -242,7 +246,8 @@ exit: static void destroy_ppp_channel(struct ppp_t *ppp) { - triton_md_unregister_handler(&ppp->chan_hnd, 1); + /* do not close chan_hnd.fd if its non-dev-ppp(chan_hnd.fd == ppp.fd) */ + triton_md_unregister_handler(&ppp->chan_hnd, !ppp->is_non_dev_ppp); close(ppp->fd); ppp->fd = -1; ppp->chan_fd = -1; @@ -292,8 +297,10 @@ static void destablish_ppp(struct ppp_t *ppp) return; } - if (ppp->is_non_dev_ppp) + if (ppp->is_non_dev_ppp) { + ppp->is_unit_read_enabled = 0; goto skip; + } if (conf_unit_cache) { struct ifreq ifr; @@ -561,18 +568,18 @@ cont: } } - list_for_each_entry(ppp_h, &ppp->unit_handlers, entry) { - if (ppp_h->proto == proto) { - if (ppp->is_unit_read_enabled > 0) { - ppp_h->recv(ppp_h); - if (ppp->fd == -1) { - ppp->ses.ctrl->finished(&ppp->ses); - return 1; - } - } - goto cont; - } - } + if (ppp->is_unit_read_enabled > 0) { + list_for_each_entry(ppp_h, &ppp->unit_handlers, entry) { + if (ppp_h->proto == proto) { + ppp_h->recv(ppp_h); + if (ppp->fd == -1) { + ppp->ses.ctrl->finished(&ppp->ses); + return 1; + } + goto cont; + } + } + } lcp_send_proto_rej(ppp, proto); log_ppp_warn("ppp_chan_and_unit_read: discarding unknown packet %x\n", proto); diff --git a/accel-pppd/session.c b/accel-pppd/session.c index 2f6a4bf..34b44cb 100644 --- a/accel-pppd/session.c +++ b/accel-pppd/session.c @@ -150,9 +150,14 @@ void __export ap_session_activate(struct ap_session *ses) if (ap_shutdown) return; - if (ses->ctrl->non_dev_ppp_fixup != NULL) - if (ses->ctrl->non_dev_ppp_fixup(ses)) - ap_session_terminate(ses, TERM_NAS_ERROR, 0); + if (ses->non_dev_ppp_fixup != NULL) { + if (!ses->non_dev_ppp_fixup_status) { + ses->non_dev_ppp_fixup(ses); + return; + } else if (ses->non_dev_ppp_fixup_status == 1) { + return; + } + } ap_session_ifup(ses); |