mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 06:15:47 +00:00
dpif-netlink: Implement conntrack zone limit
This patch provides the implementation of conntrack zone limit in dpif-netlink. It basically utilizes the netlink API to communicate with OVS kernel module to set, delete, and get conntrack zone limit. Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com> Signed-off-by: Justin Pettit <jpettit@ovn.org>
This commit is contained in:
committed by
Justin Pettit
parent
9bc339b64b
commit
906ff9d229
@@ -214,6 +214,7 @@ static int ovs_vport_family;
|
||||
static int ovs_flow_family;
|
||||
static int ovs_packet_family;
|
||||
static int ovs_meter_family;
|
||||
static int ovs_ct_limit_family;
|
||||
|
||||
/* Generic Netlink multicast groups for OVS.
|
||||
*
|
||||
@@ -2920,6 +2921,186 @@ dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
dpif_netlink_ct_set_limits(struct dpif *dpif OVS_UNUSED,
|
||||
const uint32_t *default_limits,
|
||||
const struct ovs_list *zone_limits)
|
||||
{
|
||||
struct ovs_zone_limit req_zone_limit;
|
||||
|
||||
if (ovs_ct_limit_family < 0) {
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
struct ofpbuf *request = ofpbuf_new(NL_DUMP_BUFSIZE);
|
||||
nl_msg_put_genlmsghdr(request, 0, ovs_ct_limit_family,
|
||||
NLM_F_REQUEST | NLM_F_ECHO, OVS_CT_LIMIT_CMD_SET,
|
||||
OVS_CT_LIMIT_VERSION);
|
||||
|
||||
struct ovs_header *ovs_header;
|
||||
ovs_header = ofpbuf_put_uninit(request, sizeof *ovs_header);
|
||||
ovs_header->dp_ifindex = 0;
|
||||
|
||||
size_t opt_offset;
|
||||
opt_offset = nl_msg_start_nested(request, OVS_CT_LIMIT_ATTR_ZONE_LIMIT);
|
||||
if (default_limits) {
|
||||
req_zone_limit.zone_id = OVS_ZONE_LIMIT_DEFAULT_ZONE;
|
||||
req_zone_limit.limit = *default_limits;
|
||||
nl_msg_put(request, &req_zone_limit, sizeof req_zone_limit);
|
||||
}
|
||||
|
||||
if (!ovs_list_is_empty(zone_limits)) {
|
||||
struct ct_dpif_zone_limit *zone_limit;
|
||||
|
||||
LIST_FOR_EACH (zone_limit, node, zone_limits) {
|
||||
req_zone_limit.zone_id = zone_limit->zone;
|
||||
req_zone_limit.limit = zone_limit->limit;
|
||||
nl_msg_put(request, &req_zone_limit, sizeof req_zone_limit);
|
||||
}
|
||||
}
|
||||
nl_msg_end_nested(request, opt_offset);
|
||||
|
||||
int err = nl_transact(NETLINK_GENERIC, request, NULL);
|
||||
ofpbuf_uninit(request);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
dpif_netlink_zone_limits_from_ofpbuf(const struct ofpbuf *buf,
|
||||
uint32_t *default_limit,
|
||||
struct ovs_list *zone_limits)
|
||||
{
|
||||
static const struct nl_policy ovs_ct_limit_policy[] = {
|
||||
[OVS_CT_LIMIT_ATTR_ZONE_LIMIT] = { .type = NL_A_NESTED,
|
||||
.optional = true },
|
||||
};
|
||||
|
||||
struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size);
|
||||
struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
|
||||
struct genlmsghdr *genl = ofpbuf_try_pull(&b, sizeof *genl);
|
||||
struct ovs_header *ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
|
||||
|
||||
struct nlattr *attr[ARRAY_SIZE(ovs_ct_limit_policy)];
|
||||
|
||||
if (!nlmsg || !genl || !ovs_header
|
||||
|| nlmsg->nlmsg_type != ovs_ct_limit_family
|
||||
|| !nl_policy_parse(&b, 0, ovs_ct_limit_policy, attr,
|
||||
ARRAY_SIZE(ovs_ct_limit_policy))) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
|
||||
if (!attr[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
int rem = NLA_ALIGN(
|
||||
nl_attr_get_size(attr[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]));
|
||||
const struct ovs_zone_limit *zone_limit =
|
||||
nl_attr_get(attr[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]);
|
||||
|
||||
while (rem >= sizeof *zone_limit) {
|
||||
if (zone_limit->zone_id == OVS_ZONE_LIMIT_DEFAULT_ZONE) {
|
||||
*default_limit = zone_limit->limit;
|
||||
} else if (zone_limit->zone_id < OVS_ZONE_LIMIT_DEFAULT_ZONE ||
|
||||
zone_limit->zone_id > UINT16_MAX) {
|
||||
} else {
|
||||
ct_dpif_push_zone_limit(zone_limits, zone_limit->zone_id,
|
||||
zone_limit->limit, zone_limit->count);
|
||||
}
|
||||
rem -= NLA_ALIGN(sizeof *zone_limit);
|
||||
zone_limit = ALIGNED_CAST(struct ovs_zone_limit *,
|
||||
(unsigned char *) zone_limit + NLA_ALIGN(sizeof *zone_limit));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dpif_netlink_ct_get_limits(struct dpif *dpif OVS_UNUSED,
|
||||
uint32_t *default_limit,
|
||||
const struct ovs_list *zone_limits_request,
|
||||
struct ovs_list *zone_limits_reply)
|
||||
{
|
||||
if (ovs_ct_limit_family < 0) {
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
struct ofpbuf *request = ofpbuf_new(NL_DUMP_BUFSIZE);
|
||||
nl_msg_put_genlmsghdr(request, 0, ovs_ct_limit_family,
|
||||
NLM_F_REQUEST | NLM_F_ECHO, OVS_CT_LIMIT_CMD_GET,
|
||||
OVS_CT_LIMIT_VERSION);
|
||||
|
||||
struct ovs_header *ovs_header;
|
||||
ovs_header = ofpbuf_put_uninit(request, sizeof *ovs_header);
|
||||
ovs_header->dp_ifindex = 0;
|
||||
|
||||
if (!ovs_list_is_empty(zone_limits_request)) {
|
||||
size_t opt_offset = nl_msg_start_nested(request,
|
||||
OVS_CT_LIMIT_ATTR_ZONE_LIMIT);
|
||||
|
||||
struct ovs_zone_limit req_zone_limit;
|
||||
req_zone_limit.zone_id = OVS_ZONE_LIMIT_DEFAULT_ZONE;
|
||||
nl_msg_put(request, &req_zone_limit, sizeof req_zone_limit);
|
||||
|
||||
struct ct_dpif_zone_limit *zone_limit;
|
||||
LIST_FOR_EACH (zone_limit, node, zone_limits_request) {
|
||||
req_zone_limit.zone_id = zone_limit->zone;
|
||||
nl_msg_put(request, &req_zone_limit, sizeof req_zone_limit);
|
||||
}
|
||||
|
||||
nl_msg_end_nested(request, opt_offset);
|
||||
}
|
||||
|
||||
struct ofpbuf *reply;
|
||||
int err = nl_transact(NETLINK_GENERIC, request, &reply);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = dpif_netlink_zone_limits_from_ofpbuf(reply, default_limit,
|
||||
zone_limits_reply);
|
||||
|
||||
out:
|
||||
ofpbuf_uninit(request);
|
||||
ofpbuf_uninit(reply);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
dpif_netlink_ct_del_limits(struct dpif *dpif OVS_UNUSED,
|
||||
const struct ovs_list *zone_limits)
|
||||
{
|
||||
if (ovs_ct_limit_family < 0) {
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
struct ofpbuf *request = ofpbuf_new(NL_DUMP_BUFSIZE);
|
||||
nl_msg_put_genlmsghdr(request, 0, ovs_ct_limit_family,
|
||||
NLM_F_REQUEST | NLM_F_ECHO, OVS_CT_LIMIT_CMD_DEL,
|
||||
OVS_CT_LIMIT_VERSION);
|
||||
|
||||
struct ovs_header *ovs_header;
|
||||
ovs_header = ofpbuf_put_uninit(request, sizeof *ovs_header);
|
||||
ovs_header->dp_ifindex = 0;
|
||||
|
||||
if (!ovs_list_is_empty(zone_limits)) {
|
||||
size_t opt_offset =
|
||||
nl_msg_start_nested(request, OVS_CT_LIMIT_ATTR_ZONE_LIMIT);
|
||||
|
||||
struct ct_dpif_zone_limit *zone_limit;
|
||||
LIST_FOR_EACH (zone_limit, node, zone_limits) {
|
||||
struct ovs_zone_limit req_zone_limit;
|
||||
req_zone_limit.zone_id = zone_limit->zone;
|
||||
nl_msg_put(request, &req_zone_limit, sizeof req_zone_limit);
|
||||
}
|
||||
nl_msg_end_nested(request, opt_offset);
|
||||
}
|
||||
|
||||
int err = nl_transact(NETLINK_GENERIC, request, NULL);
|
||||
|
||||
ofpbuf_uninit(request);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Meters */
|
||||
|
||||
@@ -3314,9 +3495,9 @@ const struct dpif_class dpif_netlink_class = {
|
||||
NULL, /* ct_set_maxconns */
|
||||
NULL, /* ct_get_maxconns */
|
||||
NULL, /* ct_get_nconns */
|
||||
NULL, /* ct_set_limits */
|
||||
NULL, /* ct_get_limits */
|
||||
NULL, /* ct_del_limits */
|
||||
dpif_netlink_ct_set_limits,
|
||||
dpif_netlink_ct_get_limits,
|
||||
dpif_netlink_ct_del_limits,
|
||||
dpif_netlink_meter_get_features,
|
||||
dpif_netlink_meter_set,
|
||||
dpif_netlink_meter_get,
|
||||
@@ -3356,6 +3537,12 @@ dpif_netlink_init(void)
|
||||
VLOG_INFO("The kernel module does not support meters.");
|
||||
}
|
||||
}
|
||||
if (nl_lookup_genl_family(OVS_CT_LIMIT_FAMILY,
|
||||
&ovs_ct_limit_family) < 0) {
|
||||
VLOG_INFO("Generic Netlink family '%s' does not exist. "
|
||||
"Please update the Open vSwitch kernel module to enable "
|
||||
"the conntrack limit feature.", OVS_CT_LIMIT_FAMILY);
|
||||
}
|
||||
|
||||
ovs_tunnels_out_of_tree = dpif_netlink_rtnl_probe_oot_tunnels();
|
||||
|
||||
|
Reference in New Issue
Block a user