diff --git a/include/ipvs/proto_ah_esp.h b/include/ipvs/proto_ah_esp.h new file mode 100644 index 00000000..724bc853 --- /dev/null +++ b/include/ipvs/proto_ah_esp.h @@ -0,0 +1,12 @@ +#ifndef __DP_VS_PROTO_AH_ESP_H__ +#define __DP_VS_PROTO_AH_ESP_H__ + +#define PORT_ISAKMP 500 + +enum { + DPVS_AH_ESP_S_NORMAL = 0, + DPVS_AH_ESP_S_LAST +}; + +#endif + diff --git a/src/ipvs/ip_vs_core.c b/src/ipvs/ip_vs_core.c index 63b09ab9..e3abff72 100644 --- a/src/ipvs/ip_vs_core.c +++ b/src/ipvs/ip_vs_core.c @@ -38,6 +38,7 @@ #include "ipvs/proto_udp.h" #include "route6.h" #include "ipvs/redirect.h" +#include "ipvs/proto_ah_esp.h" static inline int dp_vs_fill_iphdr(int af, struct rte_mbuf *mbuf, struct dp_vs_iphdr *iph) @@ -333,7 +334,13 @@ struct dp_vs_conn *dp_vs_schedule(struct dp_vs_service *svc, &iph->daddr, &dest->addr, ports[1], ports[0], 0, ¶m); - } else { + } else if (unlikely((iph->proto == IPPROTO_AH) || (iph->proto == IPPROTO_ESP))) { + dp_vs_conn_fill_param(iph->af, IPPROTO_UDP, + &iph->daddr, &dest->addr, + htons(PORT_ISAKMP), htons(PORT_ISAKMP), + 0, ¶m); + + } else { dp_vs_conn_fill_param(iph->af, iph->proto, &iph->saddr, &iph->daddr, ports[0], ports[1], 0, ¶m); diff --git a/src/ipvs/ip_vs_proto.c b/src/ipvs/ip_vs_proto.c index bb5baa5f..2a304ae7 100644 --- a/src/ipvs/ip_vs_proto.c +++ b/src/ipvs/ip_vs_proto.c @@ -73,6 +73,8 @@ extern struct dp_vs_proto dp_vs_proto_udp; extern struct dp_vs_proto dp_vs_proto_tcp; extern struct dp_vs_proto dp_vs_proto_icmp; extern struct dp_vs_proto dp_vs_proto_icmp6; +extern struct dp_vs_proto dp_vs_proto_esp; +extern struct dp_vs_proto dp_vs_proto_ah; int dp_vs_proto_init(void) { @@ -98,6 +100,16 @@ int dp_vs_proto_init(void) goto icmp_error; } + if ((err = proto_register(&dp_vs_proto_esp)) != EDPVS_OK) { + RTE_LOG(ERR, IPVS, "%s: fail to register ESP\n", __func__); + goto esp_error; + } + + if ((err = proto_register(&dp_vs_proto_ah)) != EDPVS_OK) { + RTE_LOG(ERR, IPVS, "%s: fail to register AH\n", __func__); + goto ah_error; + } + return EDPVS_OK; icmp_error: @@ -106,6 +118,10 @@ int dp_vs_proto_init(void) proto_unregister(&dp_vs_proto_tcp); tcp_error: proto_unregister(&dp_vs_proto_udp); +ah_error: + proto_unregister(&dp_vs_proto_ah); +esp_error: + proto_unregister(&dp_vs_proto_esp); return err; } @@ -123,5 +139,11 @@ int dp_vs_proto_term(void) if (proto_unregister(&dp_vs_proto_udp) != EDPVS_OK) RTE_LOG(ERR, IPVS, "%s: fail to unregister UDP\n", __func__); + if (proto_unregister(&dp_vs_proto_ah) != EDPVS_OK) + RTE_LOG(ERR, IPVS, "%s: fail to unregister AH\n", __func__); + + if (proto_unregister(&dp_vs_proto_esp) != EDPVS_OK) + RTE_LOG(ERR, IPVS, "%s: fail to unregister ESP\n", __func__); + return EDPVS_OK; } diff --git a/src/ipvs/ip_vs_proto_ah_esp.c b/src/ipvs/ip_vs_proto_ah_esp.c new file mode 100644 index 00000000..92d1817b --- /dev/null +++ b/src/ipvs/ip_vs_proto_ah_esp.c @@ -0,0 +1,112 @@ +/* + * DPVS is a software load balancer (Virtual Server) based on DPDK. + * + * Copyright (C) 2021 iQIYI (www.iqiyi.com). + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include "conf/common.h" +#include "dpdk.h" +#include "ipv4.h" +#include "ipv6.h" +#include "route6.h" +#include "ipvs/ipvs.h" +#include "ipvs/proto.h" +#include "ipvs/proto_ah_esp.h" +#include "ipvs/conn.h" +#include "ipvs/service.h" +#include "ipvs/blklst.h" +#include "ipvs/redirect.h" + +static int esp_timeouts[DPVS_AH_ESP_S_LAST + 1] = { + [DPVS_AH_ESP_S_NORMAL] = 300, + [DPVS_AH_ESP_S_LAST] = 2, +}; + +static int esp_conn_sched(struct dp_vs_proto *proto, + const struct dp_vs_iphdr *iph, + struct rte_mbuf *mbuf, + struct dp_vs_conn **conn, + int *verdict) +{ +/* + struct dp_vs_service *svc; + bool outwall = false; + assert(proto && iph && mbuf && conn && verdict); + + svc = dp_vs_service_lookup(iph->af, iph->proto, &iph->daddr, 0, 0, mbuf, NULL, &outwall, rte_lcore_id()); + if (!svc) { + *verdict = INET_ACCEPT; + return EDPVS_NOSERV; + } + + *conn = dp_vs_schedule(svc, iph, mbuf, false, outwall); + if (!*conn) { + *verdict = INET_DROP; + return EDPVS_RESOURCE; + } + return EDPVS_OK; +*/ + + // 在发送esp报文之前应该已经通过UDP协商报文建立会话,该流程理应永远不会走到。 + *verdict = INET_ACCEPT; + return EDPVS_DROP; +} + +static struct dp_vs_conn * +esp_conn_lookup(struct dp_vs_proto *proto, + const struct dp_vs_iphdr *iph, + struct rte_mbuf *mbuf, int *direct, + bool reverse, bool *drop, lcoreid_t *peer_cid) +{ + struct dp_vs_conn *conn; + assert(proto && iph && mbuf); + + conn = dp_vs_conn_get(iph->af, IPPROTO_UDP, + &iph->saddr, &iph->daddr, + htons(PORT_ISAKMP), htons(PORT_ISAKMP), + direct, reverse); + + return conn; +} + +static int esp_state_trans(struct dp_vs_proto *proto, struct dp_vs_conn *conn, + struct rte_mbuf *mbuf, int dir) +{ + conn->state = DPVS_AH_ESP_S_NORMAL; + conn->timeout.tv_sec = esp_timeouts[conn->state]; + return EDPVS_OK; +} + + +struct dp_vs_proto dp_vs_proto_ah = { + .name = "AH", + .proto = IPPROTO_AH, + .conn_sched = esp_conn_sched, + .conn_lookup = esp_conn_lookup, + .state_trans = esp_state_trans, +}; + +struct dp_vs_proto dp_vs_proto_esp = { + .name = "ESP", + .proto = IPPROTO_ESP, + .conn_sched = esp_conn_sched, + .conn_lookup = esp_conn_lookup, + .state_trans = esp_state_trans, +}; + +