diff options
author | Tobias Brunner <tobias@strongswan.org> | 2017-05-23 17:00:04 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2017-05-23 17:00:04 +0200 |
commit | 6b9361f71418239fb0835e9ff5bf0b1816f9dc04 (patch) | |
tree | ed9ce9dd7faab3e99ed2ea7a00dac14c2594f21f /src/libcharon/plugins | |
parent | 7caec9e4a40142803f22ed195704cdd46b097db1 (diff) | |
parent | 48ea65501668bbae49a0ab48001ee15fe95b657e (diff) | |
download | strongswan-6b9361f71418239fb0835e9ff5bf0b1816f9dc04.tar.bz2 strongswan-6b9361f71418239fb0835e9ff5bf0b1816f9dc04.tar.xz |
Merge branch 'hw-offload'
Allows enabling hardware offload for IPsec SAs as introduced by Linux 4.11
for specific hardware.
Diffstat (limited to 'src/libcharon/plugins')
-rw-r--r-- | src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c | 87 | ||||
-rw-r--r-- | src/libcharon/plugins/sql/sql_config.c | 4 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_config.c | 8 | ||||
-rw-r--r-- | src/libcharon/plugins/stroke/stroke_list.c | 2 | ||||
-rw-r--r-- | src/libcharon/plugins/updown/updown_listener.c | 2 | ||||
-rw-r--r-- | src/libcharon/plugins/vici/vici_config.c | 80 | ||||
-rw-r--r-- | src/libcharon/plugins/vici/vici_query.c | 2 |
7 files changed, 147 insertions, 38 deletions
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index becf6b5dc..9a40927d2 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1639,6 +1639,31 @@ METHOD(kernel_ipsec_t, add_sa, status_t, data->replay_window); sa->replay_window = data->replay_window; } + if (data->hw_offload) + { + host_t *local = data->inbound ? id->dst : id->src; + char *ifname; + + if (charon->kernel->get_interface(charon->kernel, local, &ifname)) + { + struct xfrm_user_offload *offload; + + offload = netlink_reserve(hdr, sizeof(request), + XFRMA_OFFLOAD_DEV, sizeof(*offload)); + if (!offload) + { + free(ifname); + goto failed; + } + offload->ifindex = if_nametoindex(ifname); + if (local->get_family(local) == AF_INET6) + { + offload->flags |= XFRM_OFFLOAD_IPV6; + } + offload->flags |= data->inbound ? XFRM_OFFLOAD_INBOUND : 0; + free(ifname); + } + } } if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) @@ -1919,13 +1944,13 @@ METHOD(kernel_ipsec_t, update_sa, status_t, kernel_ipsec_update_sa_t *data) { netlink_buf_t request; - struct nlmsghdr *hdr, *out = NULL; + struct nlmsghdr *hdr, *out_hdr = NULL, *out = NULL; struct xfrm_usersa_id *sa_id; - struct xfrm_usersa_info *out_sa = NULL, *sa; + struct xfrm_usersa_info *sa; size_t len; struct rtattr *rta; size_t rtasize; - struct xfrm_encap_tmpl* tmpl = NULL; + struct xfrm_encap_tmpl* encap = NULL; struct xfrm_replay_state *replay = NULL; struct xfrm_replay_state_esn *replay_esn = NULL; struct xfrm_lifetime_cur *lifetime = NULL; @@ -1983,7 +2008,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, { case XFRM_MSG_NEWSA: { - out_sa = NLMSG_DATA(hdr); + out_hdr = hdr; break; } case NLMSG_ERROR: @@ -2002,7 +2027,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, break; } } - if (out_sa == NULL) + if (!out_hdr) { DBG1(DBG_KNL, "unable to update SAD entry with SPI %.8x%s", ntohl(id->spi), markstr); @@ -2029,7 +2054,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, hdr->nlmsg_type = XFRM_MSG_NEWSA; hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)); sa = NLMSG_DATA(hdr); - memcpy(sa, NLMSG_DATA(out), sizeof(struct xfrm_usersa_info)); + memcpy(sa, NLMSG_DATA(out_hdr), sizeof(struct xfrm_usersa_info)); sa->family = data->new_dst->get_family(data->new_dst); if (!id->src->ip_equals(id->src, data->new_src)) @@ -2041,8 +2066,8 @@ METHOD(kernel_ipsec_t, update_sa, status_t, host2xfrm(data->new_dst, &sa->id.daddr); } - rta = XFRM_RTA(out, struct xfrm_usersa_info); - rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info); + rta = XFRM_RTA(out_hdr, struct xfrm_usersa_info); + rtasize = XFRM_PAYLOAD(out_hdr, struct xfrm_usersa_info); while (RTA_OK(rta, rtasize)) { /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */ @@ -2050,9 +2075,34 @@ METHOD(kernel_ipsec_t, update_sa, status_t, { if (rta->rta_type == XFRMA_ENCAP) { /* update encap tmpl */ - tmpl = RTA_DATA(rta); - tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src)); - tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst)); + encap = RTA_DATA(rta); + encap->encap_sport = ntohs(data->new_src->get_port(data->new_src)); + encap->encap_dport = ntohs(data->new_dst->get_port(data->new_dst)); + } + if (rta->rta_type == XFRMA_OFFLOAD_DEV) + { /* update offload device */ + struct xfrm_user_offload *offload; + host_t *local; + char *ifname; + + offload = RTA_DATA(rta); + local = offload->flags & XFRM_OFFLOAD_INBOUND ? data->new_dst + : data->new_src; + + if (charon->kernel->get_interface(charon->kernel, local, + &ifname)) + { + offload->ifindex = if_nametoindex(ifname); + if (local->get_family(local) == AF_INET6) + { + offload->flags |= XFRM_OFFLOAD_IPV6; + } + else + { + offload->flags &= ~XFRM_OFFLOAD_IPV6; + } + free(ifname); + } } netlink_add_attribute(hdr, rta->rta_type, chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)), @@ -2061,17 +2111,18 @@ METHOD(kernel_ipsec_t, update_sa, status_t, rta = RTA_NEXT(rta, rtasize); } - if (tmpl == NULL && data->new_encap) + if (encap == NULL && data->new_encap) { /* add tmpl if we are enabling it */ - tmpl = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, sizeof(*tmpl)); - if (!tmpl) + encap = netlink_reserve(hdr, sizeof(request), XFRMA_ENCAP, + sizeof(*encap)); + if (!encap) { goto failed; } - tmpl->encap_type = UDP_ENCAP_ESPINUDP; - tmpl->encap_sport = ntohs(data->new_src->get_port(data->new_src)); - tmpl->encap_dport = ntohs(data->new_dst->get_port(data->new_dst)); - memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t)); + encap->encap_type = UDP_ENCAP_ESPINUDP; + encap->encap_sport = ntohs(data->new_src->get_port(data->new_src)); + encap->encap_dport = ntohs(data->new_dst->get_port(data->new_dst)); + memset(&encap->encap_oa, 0, sizeof (xfrm_address_t)); } if (replay_esn) diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c index 88cac7f26..cf7c3b814 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -173,7 +173,8 @@ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e) child_cfg_create_t child = { .mode = mode, .reqid = reqid, - .ipcomp = ipcomp, + .options = (ipcomp ? OPT_IPCOMP : 0) | + (hostaccess ? OPT_HOSTACCESS : 0), .lifetime = { .time = { .life = lifetime, .rekey = rekeytime, .jitter = jitter @@ -183,7 +184,6 @@ static child_cfg_t *build_child_cfg(private_sql_config_t *this, enumerator_t *e) .dpd_action = dpd, .close_action = close, .updown = updown, - .hostaccess = hostaccess, }; child_cfg = child_cfg_create(name, &child); add_esp_proposals(this, child_cfg, id); diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index bbdc2116d..a9d073684 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -1071,15 +1071,15 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this, }, .reqid = msg->add_conn.reqid, .mode = msg->add_conn.mode, - .proxy_mode = msg->add_conn.proxy_mode, - .ipcomp = msg->add_conn.ipcomp, + .options = (msg->add_conn.proxy_mode ? OPT_PROXY_MODE : 0) | + (msg->add_conn.ipcomp ? OPT_IPCOMP : 0) | + (msg->add_conn.me.hostaccess ? OPT_HOSTACCESS : 0) | + (msg->add_conn.install_policy ? 0 : OPT_NO_POLICIES), .tfc = msg->add_conn.tfc, .inactivity = msg->add_conn.inactivity, .dpd_action = map_action(msg->add_conn.dpd.action), .close_action = map_action(msg->add_conn.close_action), .updown = msg->add_conn.me.updown, - .hostaccess = msg->add_conn.me.hostaccess, - .suppress_policies = !msg->add_conn.install_policy, }; child_cfg = child_cfg_create(msg->add_conn.name, &child); diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index 92e368669..a33316658 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -218,7 +218,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa), child_sa_state_names, child_sa->get_state(child_sa), ipsec_mode_names, child_sa->get_mode(child_sa), - config->use_proxy_mode(config) ? "_PROXY" : "", + config->has_option(config, OPT_PROXY_MODE) ? "_PROXY" : "", child_sa->get_reqid(child_sa)); if (child_sa->get_state(child_sa) == CHILD_INSTALLED) diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c index 6a1581c85..bbefd6a02 100644 --- a/src/libcharon/plugins/updown/updown_listener.c +++ b/src/libcharon/plugins/updown/updown_listener.c @@ -366,7 +366,7 @@ static void invoke_once(private_updown_listener_t *this, ike_sa_t *ike_sa, push_env(envp, countof(envp), "PLUTO_IPCOMP=1"); } push_dns_env(this, ike_sa, envp, countof(envp)); - if (config->get_hostaccess(config)) + if (config->has_option(config, OPT_HOSTACCESS)) { push_env(envp, countof(envp), "PLUTO_HOST_ACCESS=1"); } diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index baa350784..46eaf5cff 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -478,7 +478,6 @@ typedef struct { linked_list_t *remote_ts; uint32_t replay_window; bool policies; - bool policies_fwd_out; child_cfg_create_t cfg; } child_data_t; @@ -500,12 +499,12 @@ static void log_child_data(child_data_t *data, char *name) DBG2(DBG_CFG, " life_packets = %llu", cfg->lifetime.packets.life); DBG2(DBG_CFG, " rand_packets = %llu", cfg->lifetime.packets.jitter); DBG2(DBG_CFG, " updown = %s", cfg->updown); - DBG2(DBG_CFG, " hostaccess = %u", cfg->hostaccess); - DBG2(DBG_CFG, " ipcomp = %u", cfg->ipcomp); + DBG2(DBG_CFG, " hostaccess = %u", cfg->options & OPT_HOSTACCESS); + DBG2(DBG_CFG, " ipcomp = %u", cfg->options & OPT_IPCOMP); DBG2(DBG_CFG, " mode = %N%s", ipsec_mode_names, cfg->mode, - cfg->proxy_mode ? "_PROXY" : ""); + cfg->options & OPT_PROXY_MODE ? "_PROXY" : ""); DBG2(DBG_CFG, " policies = %u", data->policies); - DBG2(DBG_CFG, " policies_fwd_out = %u", data->policies_fwd_out); + DBG2(DBG_CFG, " policies_fwd_out = %u", cfg->options & OPT_FWD_OUT_POLICIES); if (data->replay_window != REPLAY_UNDEFINED) { DBG2(DBG_CFG, " replay_window = %u", data->replay_window); @@ -525,6 +524,7 @@ static void log_child_data(child_data_t *data, char *name) DBG2(DBG_CFG, " proposals = %#P", data->proposals); DBG2(DBG_CFG, " local_ts = %#R", data->local_ts); DBG2(DBG_CFG, " remote_ts = %#R", data->remote_ts); + DBG2(DBG_CFG, " hw_offload = %u", cfg->options & OPT_HW_OFFLOAD); } /** @@ -827,13 +827,71 @@ CALLBACK(parse_mode, bool, if (parse_map(map, countof(map), &d, v)) { cfg->mode = d; - cfg->proxy_mode = (d == MODE_TRANSPORT) && (v.len > 9); + if ((d == MODE_TRANSPORT) && (v.len > 9)) + { + cfg->options |= OPT_PROXY_MODE; + } return TRUE; } return FALSE; } /** + * Enable a child_cfg_option_t + */ +static bool parse_option(child_cfg_option_t *out, child_cfg_option_t opt, + chunk_t v) +{ + bool val; + + if (parse_bool(&val, v)) + { + if (val) + { + *out |= opt; + } + return TRUE; + } + return FALSE; +} + +/** + * Parse OPT_HOSTACCESS option + */ +CALLBACK(parse_opt_haccess, bool, + child_cfg_option_t *out, chunk_t v) +{ + return parse_option(out, OPT_HOSTACCESS, v); +} + +/** + * Parse OPT_FWD_OUT_POLICIES option + */ +CALLBACK(parse_opt_fwd_out, bool, + child_cfg_option_t *out, chunk_t v) +{ + return parse_option(out, OPT_FWD_OUT_POLICIES, v); +} + +/** + * Parse OPT_FWD_OUT_POLICIES option + */ +CALLBACK(parse_opt_ipcomp, bool, + child_cfg_option_t *out, chunk_t v) +{ + return parse_option(out, OPT_IPCOMP, v); +} + +/** + * Parse OPT_HW_OFFLOAD option + */ +CALLBACK(parse_opt_hw_offl, bool, + child_cfg_option_t *out, chunk_t v) +{ + return parse_option(out, OPT_HW_OFFLOAD, v); +} + +/** * Parse an action_t */ CALLBACK(parse_action, bool, @@ -1466,10 +1524,10 @@ CALLBACK(child_kv, bool, { parse_rule_t rules[] = { { "updown", parse_string, &child->cfg.updown }, - { "hostaccess", parse_bool, &child->cfg.hostaccess }, + { "hostaccess", parse_opt_haccess, &child->cfg.options }, { "mode", parse_mode, &child->cfg }, { "policies", parse_bool, &child->policies }, - { "policies_fwd_out", parse_bool, &child->policies_fwd_out }, + { "policies_fwd_out", parse_opt_fwd_out, &child->cfg.options }, { "replay_window", parse_uint32, &child->replay_window }, { "rekey_time", parse_time, &child->cfg.lifetime.time.rekey }, { "life_time", parse_time, &child->cfg.lifetime.time.life }, @@ -1483,7 +1541,7 @@ CALLBACK(child_kv, bool, { "dpd_action", parse_action, &child->cfg.dpd_action }, { "start_action", parse_action, &child->cfg.start_action }, { "close_action", parse_action, &child->cfg.close_action }, - { "ipcomp", parse_bool, &child->cfg.ipcomp }, + { "ipcomp", parse_opt_ipcomp, &child->cfg.options }, { "inactivity", parse_time, &child->cfg.inactivity }, { "reqid", parse_uint32, &child->cfg.reqid }, { "mark_in", parse_mark, &child->cfg.mark_in }, @@ -1491,6 +1549,7 @@ CALLBACK(child_kv, bool, { "tfc_padding", parse_tfc, &child->cfg.tfc }, { "priority", parse_uint32, &child->cfg.priority }, { "interface", parse_string, &child->cfg.interface }, + { "hw_offload", parse_opt_hw_offl, &child->cfg.options }, }; return parse_rules(rules, countof(rules), name, value, @@ -1756,8 +1815,7 @@ CALLBACK(children_sn, bool, child.proposals->insert_last(child.proposals, proposal); } } - child.cfg.suppress_policies = !child.policies; - child.cfg.fwd_out_policies = child.policies_fwd_out; + child.cfg.options |= child.policies ? 0 : OPT_NO_POLICIES; check_lifetimes(&child.cfg.lifetime); diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c index c0f4e2de9..2cc59591f 100644 --- a/src/libcharon/plugins/vici/vici_query.c +++ b/src/libcharon/plugins/vici/vici_query.c @@ -107,7 +107,7 @@ static void list_mode(vici_builder_t *b, child_sa_t *child, child_cfg_t *cfg) cfg = child->get_config(child); } mode = child ? child->get_mode(child) : cfg->get_mode(cfg); - if (mode == MODE_TRANSPORT && cfg->use_proxy_mode(cfg)) + if (mode == MODE_TRANSPORT && cfg->has_option(cfg, OPT_PROXY_MODE)) { /* only report this if the negotiated mode is actually TRANSPORT */ sub_mode = "_PROXY"; } |