Skip to content

Commit

Permalink
Broadcast vrouter operations on netlink
Browse files Browse the repository at this point in the history
This patch introduces the netlink broadcasting of operations on vrouter
routes. For instance, when a route is added by a client, the vrouter
broadcasts the request on netlink.

We currently broadcast 'add' and 'delete' operations on the resource
route.

This allows the userspace to be notified by any modifcation on routes,
in the same manner it is notified by the Linux network stack thanks to
'ip monitor' for instance.

Change-Id: Ifed994e552b35faa771d4b6dad6da7eea1cecdfb
Closes-bug: #1650316
  • Loading branch information
Antoine Eiche committed Mar 30, 2017
1 parent 02e68e0 commit 0399c8c
Show file tree
Hide file tree
Showing 19 changed files with 96 additions and 46 deletions.
2 changes: 1 addition & 1 deletion dp-core/vr_bridge.c
Expand Up @@ -581,7 +581,7 @@ vr_bridge_table_data_process(void *s_req)
}

generate_response:
vr_message_response(VR_BRIDGE_TABLE_DATA_OBJECT_ID, resp, ret);
vr_message_response(VR_BRIDGE_TABLE_DATA_OBJECT_ID, resp, ret, false);
if (resp) {
vr_bridge_table_data_destroy(resp);
resp = NULL;
Expand Down
4 changes: 2 additions & 2 deletions dp-core/vr_flow.c
Expand Up @@ -2396,7 +2396,7 @@ vr_flow_table_data_process(void *s_req)
resp->ftable_hold_entries = vr_flow_table_hold_count(router);

send_response:
vr_message_response(VR_FLOW_TABLE_DATA_OBJECT_ID, resp, ret);
vr_message_response(VR_FLOW_TABLE_DATA_OBJECT_ID, resp, ret, false);
if (resp)
vr_flow_table_data_destroy(resp);

Expand Down Expand Up @@ -2428,7 +2428,7 @@ vr_flow_req_process(void *s_req)
ret = -EINVAL;
}

vr_message_response(VR_FLOW_RESPONSE_OBJECT_ID, &flow_resp, ret);
vr_message_response(VR_FLOW_RESPONSE_OBJECT_ID, &flow_resp, ret, false);

return;
}
Expand Down
24 changes: 18 additions & 6 deletions dp-core/vr_message.c
Expand Up @@ -77,7 +77,7 @@ vr_message_request(struct vr_message *message)
}

static int
vr_message_queue_response(char *buf, int len)
vr_message_queue_response(char *buf, int len, bool broadcast)
{
struct vr_message *response;

Expand All @@ -87,6 +87,7 @@ vr_message_queue_response(char *buf, int len)

response->vr_message_buf = buf;
response->vr_message_len = len;
response->vr_message_broadcast = broadcast;
vr_queue_enqueue(&message_h.vm_response_queue,
&response->vr_message_queue);

Expand Down Expand Up @@ -224,7 +225,7 @@ vr_message_multi_response(struct vr_message_multi *objects)
len += ret;
}

return vr_message_queue_response(buf, len);
return vr_message_queue_response(buf, len, false);

response_fail:
if (buf)
Expand All @@ -236,7 +237,7 @@ vr_message_multi_response(struct vr_message_multi *objects)
}

int
vr_message_response(unsigned int object_type, void *object, int ret)
vr_message_response(unsigned int object_type, void *object, int ret, bool broadcast)
{
char *buf = NULL;
unsigned int len = 0;
Expand All @@ -261,7 +262,7 @@ vr_message_response(unsigned int object_type, void *object, int ret)
if (ret < 0)
goto response_fail;

return vr_message_queue_response(buf, ret);
return vr_message_queue_response(buf, ret, broadcast);

response_fail:
if (buf)
Expand All @@ -274,7 +275,18 @@ vr_message_response(unsigned int object_type, void *object, int ret)
int
vr_send_response(int code)
{
return vr_message_response(VR_NULL_OBJECT_ID, NULL, code);
return vr_message_response(VR_NULL_OBJECT_ID, NULL, code, false);
}

int
vr_send_broadcast(unsigned int object_type, void *object, unsigned int sandesh_op, int code)
{
if (!vr_nl_broadcast_supported)
return 0;
// We only broadcast requests that have succeeded
if (code >= 0)
return vr_message_response(object_type, object, code, true);
return code;
}

int
Expand Down Expand Up @@ -327,7 +339,7 @@ vr_message_dump_exit(void *context, int ret)
trans->mtrans_free(dumper->dump_buffer);
} else
vr_message_queue_response(dumper->dump_buffer,
dumper->dump_offset);
dumper->dump_offset, false);

vr_free(dumper, VR_MESSAGE_DUMP_OBJECT);
}
Expand Down
2 changes: 1 addition & 1 deletion dp-core/vr_mirror.c
Expand Up @@ -210,7 +210,7 @@ vr_mirror_get(vr_mirror_req *req)
} else
req = NULL;

return vr_message_response(VR_MIRROR_OBJECT_ID, req, ret);
return vr_message_response(VR_MIRROR_OBJECT_ID, req, ret, false);
}

void
Expand Down
2 changes: 1 addition & 1 deletion dp-core/vr_mpls.c
Expand Up @@ -215,7 +215,7 @@ vr_mpls_get(vr_mpls_req *req)
if (ret)
req = NULL;

vr_message_response(VR_MPLS_OBJECT_ID, req, ret);
vr_message_response(VR_MPLS_OBJECT_ID, req, ret, false);

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion dp-core/vr_nexthop.c
Expand Up @@ -3561,7 +3561,7 @@ vr_nexthop_get(vr_nexthop_req *req)
ret = -ENOENT;

generate_response:
vr_message_response(VR_NEXTHOP_OBJECT_ID, ret < 0 ? NULL : resp, ret);
vr_message_response(VR_NEXTHOP_OBJECT_ID, ret < 0 ? NULL : resp, ret, false);
if (resp)
vr_nexthop_req_destroy(resp);

Expand Down
4 changes: 2 additions & 2 deletions dp-core/vr_qos.c
Expand Up @@ -345,7 +345,7 @@ vr_qos_map_get(vr_qos_map_req *req)
}

vr_qos_map_make_req(req->qmr_id, resp, fc_p);
vr_message_response(VR_QOS_MAP_OBJECT_ID, resp, ret);
vr_message_response(VR_QOS_MAP_OBJECT_ID, resp, ret, false);
if (resp) {
vr_qos_map_req_destroy(resp);
}
Expand Down Expand Up @@ -663,7 +663,7 @@ vr_fc_map_get(vr_fc_map_req *req)
resp->fmr_queue_id[0] = fc_p->vfc_queue_id;

generate_response:
vr_message_response(VR_FC_MAP_OBJECT_ID, ret < 0 ? NULL : resp, ret);
vr_message_response(VR_FC_MAP_OBJECT_ID, ret < 0 ? NULL : resp, ret, false);
if (resp)
vr_fc_map_req_destroy(resp);

Expand Down
6 changes: 4 additions & 2 deletions dp-core/vr_route.c
Expand Up @@ -82,6 +82,7 @@ vr_route_delete(vr_route_req *req)

error:
vr_send_response(ret);
vr_send_broadcast(VR_ROUTE_OBJECT_ID, &vr_req, SANDESH_OP_DELETE, ret);

return ret;
}
Expand Down Expand Up @@ -112,6 +113,7 @@ vr_route_add(vr_route_req *req)
}

vr_send_response(ret);
vr_send_broadcast(VR_ROUTE_OBJECT_ID, &vr_req, SANDESH_OP_ADD, ret);

return ret;
}
Expand Down Expand Up @@ -166,7 +168,7 @@ vr_route_get(vr_route_req *req)
}

generate_response:
vr_message_response(VR_ROUTE_OBJECT_ID, ret ? NULL : &vr_req, ret);
vr_message_response(VR_ROUTE_OBJECT_ID, ret ? NULL : &vr_req, ret, false);
if (mac_mem_free && vr_req.rtr_req.rtr_mac) {
vr_free(vr_req.rtr_req.rtr_mac, VR_ROUTE_REQ_MAC_OBJECT);
vr_req.rtr_req.rtr_mac = NULL;
Expand Down Expand Up @@ -298,7 +300,7 @@ vr_inet_vrf_stats_get(struct vrouter *router, vr_vrf_stats_req *req)

ret = rtable->algo_stats_get(req, &response);
generate_error:
vr_message_response(VR_VRF_STATS_OBJECT_ID, ret ? NULL : &response, ret);
vr_message_response(VR_VRF_STATS_OBJECT_ID, ret ? NULL : &response, ret, false);
return;
}

Expand Down
4 changes: 2 additions & 2 deletions dp-core/vr_stats.c
Expand Up @@ -134,7 +134,7 @@ vr_drop_stats_get(unsigned int rid, short core)
/* otherwise the counters will be zeros */

exit_get:
vr_message_response(VR_DROP_STATS_OBJECT_ID, ret ? NULL : response, ret);
vr_message_response(VR_DROP_STATS_OBJECT_ID, ret ? NULL : response, ret, false);

if (response != NULL)
vr_free(response, VR_DROP_STATS_REQ_OBJECT);
Expand Down Expand Up @@ -324,7 +324,7 @@ vr_mem_stats_get(void)
response->vms_freed = freed;

exit_get:
vr_message_response(VR_MEM_STATS_OBJECT_ID, ret ? NULL : response, ret);
vr_message_response(VR_MEM_STATS_OBJECT_ID, ret ? NULL : response, ret, false);
if (response != NULL)
vr_free(response, VR_MEM_STATS_REQ_OBJECT);

Expand Down
2 changes: 1 addition & 1 deletion dp-core/vr_vrf_assign.c
Expand Up @@ -71,7 +71,7 @@ vr_vrf_assign_get(vr_vrf_assign_req *req)
ret = vif_vrf_table_get(vif, &resp);
vrouter_put_interface(vif);
exit_get:
vr_message_response(VR_VRF_ASSIGN_OBJECT_ID, ret ? NULL : &resp, ret);
vr_message_response(VR_VRF_ASSIGN_OBJECT_ID, ret ? NULL : &resp, ret, false);
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion dp-core/vr_vxlan.c
Expand Up @@ -152,7 +152,7 @@ vr_vxlan_get(vr_vxlan_req *req)
else
req = NULL;

vr_message_response(VR_VXLAN_OBJECT_ID, req, ret);
vr_message_response(VR_VXLAN_OBJECT_ID, req, ret, false);

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion dp-core/vrouter.c
Expand Up @@ -374,7 +374,7 @@ vrouter_ops_get_process(void *s_req)
if (ret)
req = NULL;

vr_message_response(VR_VROUTER_OPS_OBJECT_ID, req, ret);
vr_message_response(VR_VROUTER_OPS_OBJECT_ID, req, ret, false);
if (resp)
vrouter_ops_destroy(resp);

Expand Down
1 change: 1 addition & 0 deletions dpdk/vr_dpdk_host.c
Expand Up @@ -1344,6 +1344,7 @@ struct host_os dpdk_host = {
.hos_get_enabled_log_types = dpdk_get_enabled_log_types,
.hos_soft_reset = dpdk_soft_reset,
.hos_is_frag_limit_exceeded = dpdk_is_frag_limit_exceeded,
.hos_nl_broadcast_supported = false,
};

struct host_os *
Expand Down
1 change: 1 addition & 0 deletions freebsd/vrouter_mod.c
Expand Up @@ -715,6 +715,7 @@ struct host_os freebsd_host = {
.hos_set_log_type = fh_set_log_type,
.hos_get_log_level = fh_get_log_level,
.hos_get_enabled_log_types = fh_get_enabled_log_types,
.hos_nl_broadcast_supported = false,
};

struct host_os *
Expand Down
3 changes: 2 additions & 1 deletion include/vr_message.h
Expand Up @@ -56,6 +56,7 @@ struct vr_mtransport {
struct vr_message {
char *vr_message_buf;
unsigned int vr_message_len;
bool vr_message_broadcast;
struct vr_qelem vr_message_queue;
};

Expand Down Expand Up @@ -93,7 +94,7 @@ struct vr_message_dumper *vr_message_dump_init(void *);
void vr_message_dump_exit(void *, int);

int vr_message_request(struct vr_message *);
int vr_message_response(unsigned int, void *, int);
int vr_message_response(unsigned int, void *, int, bool);
int vr_message_multi_response(struct vr_message_multi *);
int vr_message_make_request(unsigned int, void *);
int vr_message_process_response(int (*)(void *, unsigned int, void *), void *);
Expand Down
1 change: 1 addition & 0 deletions include/vr_response.h
Expand Up @@ -9,6 +9,7 @@
#include <vr_types.h>

extern int vr_send_response(int);
extern int vr_send_broadcast(unsigned int, void *, unsigned int, int);
extern int vr_generate_response(vr_response *, int, unsigned char *, int);

#endif /* __VR_RESPONSE_H__ */
2 changes: 2 additions & 0 deletions include/vrouter.h
Expand Up @@ -217,6 +217,7 @@ struct host_os {
unsigned int *(*hos_get_enabled_log_types)(int *);
void (*hos_soft_reset)(struct vrouter *);
int (*hos_is_frag_limit_exceeded)(void);
bool hos_nl_broadcast_supported;
};

#define vr_printf vrouter_host->hos_printf
Expand Down Expand Up @@ -265,6 +266,7 @@ struct host_os {
#define vr_get_log_level vrouter_host->hos_get_log_level
#define vr_get_enabled_log_types vrouter_host->hos_get_enabled_log_types
#define vr_soft_reset vrouter_host->hos_soft_reset
#define vr_nl_broadcast_supported vrouter_host->hos_nl_broadcast_supported

struct vr_malloc_stats {
int64_t ms_size;
Expand Down
77 changes: 53 additions & 24 deletions linux/vr_genetlink.c
Expand Up @@ -18,6 +18,7 @@
#include "vr_message.h"
#include "sandesh.h"
#include "vr_response.h"
#include "vrouter.h"

static int netlink_trans_request(struct sk_buff *, struct genl_info *);

Expand All @@ -37,6 +38,10 @@ struct genl_family vrouter_genl_family = {
.netnsok = true,
};

struct genl_multicast_group vrouter_genl_groups[] = {
{ .name = "VRouterGroup" },
};

#define NETLINK_RESPONSE_HEADER_LEN (NLMSG_HDRLEN + GENL_HDRLEN + \
NLA_HDRLEN)
#define NETLINK_BUFFER(skb_data) ((char *)skb_data + \
Expand Down Expand Up @@ -93,6 +98,7 @@ netlink_trans_request(struct sk_buff *in_skb, struct genl_info *info)
struct vr_message request, *response;
struct sk_buff *skb;
uint32_t netlink_id;
void *msg_head;

if (!aap || !(nla = aap[NL_ATTR_VR_MESSAGE_PROTOCOL]))
return -EINVAL;
Expand All @@ -114,28 +120,51 @@ netlink_trans_request(struct sk_buff *in_skb, struct genl_info *info)

multi_flag = 0;
while ((response = vr_message_dequeue_response())) {
if ((multi_flag == 0) && (!vr_response_queue_empty()))
multi_flag = NLM_F_MULTI;

buf = response->vr_message_buf;
skb = netlink_skb(buf);
if (!skb)
continue;

len = response->vr_message_len;
len += GENL_HDRLEN + NLA_HDRLEN;
len = NLMSG_ALIGN(len);
rep = __nlmsg_put(skb, netlink_id, nlh->nlmsg_seq,
nlh->nlmsg_type, len, multi_flag);
genlh = nlmsg_data(rep);
memcpy(genlh, info->genlhdr, sizeof(*genlh));

nla = (struct nlattr *)((char *)genlh + GENL_HDRLEN);
nla->nla_len = response->vr_message_len;
nla->nla_type = NL_ATTR_VR_MESSAGE_PROTOCOL;

netlink_unicast(in_skb->sk, skb, netlink_id, MSG_DONTWAIT);

if (!response->vr_message_broadcast) {
if ((multi_flag == 0) && (!vr_response_queue_empty()))
multi_flag = NLM_F_MULTI;

buf = response->vr_message_buf;
skb = netlink_skb(buf);
if (!skb)
goto next;

len = response->vr_message_len;
len += GENL_HDRLEN + NLA_HDRLEN;
len = NLMSG_ALIGN(len);
rep = __nlmsg_put(skb, netlink_id, nlh->nlmsg_seq,
nlh->nlmsg_type, len, multi_flag);
genlh = nlmsg_data(rep);
memcpy(genlh, info->genlhdr, sizeof(*genlh));

nla = (struct nlattr *)((char *)genlh + GENL_HDRLEN);
nla->nla_len = response->vr_message_len;
nla->nla_type = NL_ATTR_VR_MESSAGE_PROTOCOL;

netlink_unicast(in_skb->sk, skb, netlink_id, MSG_DONTWAIT);
} else {
// If there is no listener, we don't broadcast
if (!netlink_has_listeners(in_skb->sk, vrouter_genl_family.mcgrp_offset)) {
goto next;
}

skb = genlmsg_new(nla->nla_len, GFP_KERNEL);
if (!skb)
goto next;
msg_head = genlmsg_put(skb, 0, 0, &vrouter_genl_family, 0, SANDESH_REQUEST);
if (!msg_head) {
nlmsg_free(skb);
goto next;
}
if (nla_put(skb, NL_ATTR_VR_MESSAGE_PROTOCOL, response->vr_message_len, response->vr_message_buf) < 0) {
nlmsg_free(skb);
goto next;
}
genlmsg_end(skb, msg_head);

genlmsg_multicast(&vrouter_genl_family, skb, 0, 0, GFP_KERNEL);
}
next:
response->vr_message_buf = NULL;
vr_message_free(response);
}
Expand Down Expand Up @@ -181,7 +210,7 @@ vr_genetlink_init(void)
return genl_register_family_with_ops(&vrouter_genl_family, vrouter_genl_ops,
ARRAY_SIZE(vrouter_genl_ops));
#else
return genl_register_family_with_ops(&vrouter_genl_family,
vrouter_genl_ops);
return genl_register_family_with_ops_groups(&vrouter_genl_family,
vrouter_genl_ops, vrouter_genl_groups);
#endif
}
1 change: 1 addition & 0 deletions linux/vrouter_mod.c
Expand Up @@ -2249,6 +2249,7 @@ struct host_os linux_host = {
.hos_get_log_level = lh_get_log_level,
.hos_get_enabled_log_types = lh_get_enabled_log_types,
.hos_soft_reset = lh_soft_reset,
.hos_nl_broadcast_supported = true,
};

struct host_os *
Expand Down

0 comments on commit 0399c8c

Please sign in to comment.