Skip to content

Commit

Permalink
ovs-router: introduce pkt-mark.
Browse files Browse the repository at this point in the history
OVS router is basically partial copy of linux kernel FIB.
kernel routing table uses skb-mark along with usual routing
parameters. Following patch brings in support for skb-mark
to ovs-router so that we can lookup route for given skb-mark.

Signed-off-by: Pravin B Shelar <[email protected]>
Acked-by: Jarno Rajahalme <[email protected]>
  • Loading branch information
pshelar committed Jan 28, 2017
1 parent f36786c commit ed52ca5
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 42 deletions.
4 changes: 3 additions & 1 deletion lib/netdev-vport.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,12 @@ tunnel_check_status_change__(struct netdev_vport *netdev)
bool status = false;
struct in6_addr *route;
struct in6_addr gw;
uint32_t mark;

iface[0] = '\0';
route = &netdev->tnl_cfg.ipv6_dst;
if (ovs_router_lookup(route, iface, NULL, &gw)) {
mark = netdev->tnl_cfg.egress_pkt_mark;
if (ovs_router_lookup(mark, route, iface, NULL, &gw)) {
struct netdev *egress_netdev;

if (!netdev_open(iface, NULL, &egress_netdev)) {
Expand Down
125 changes: 89 additions & 36 deletions lib/ovs-router.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@
#include "unaligned.h"
#include "unixctl.h"
#include "util.h"
#include "openvswitch/vlog.h"

VLOG_DEFINE_THIS_MODULE(ovs_router);

static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);

static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
static struct classifier cls;
Expand All @@ -57,6 +62,7 @@ struct ovs_router_entry {
struct in6_addr src_addr;
uint8_t plen;
uint8_t priority;
uint32_t mark;
};

static struct ovs_router_entry *
Expand Down Expand Up @@ -88,11 +94,12 @@ ovs_router_lookup_fallback(const struct in6_addr *ip6_dst, char output_bridge[],
}

bool
ovs_router_lookup(const struct in6_addr *ip6_dst, char output_bridge[],
ovs_router_lookup(uint32_t mark, const struct in6_addr *ip6_dst,
char output_bridge[],
struct in6_addr *src, struct in6_addr *gw)
{
const struct cls_rule *cr;
struct flow flow = {.ipv6_dst = *ip6_dst};
struct flow flow = {.ipv6_dst = *ip6_dst, .pkt_mark = mark};

cr = classifier_lookup(&cls, OVS_VERSION_MAX, &flow, NULL);
if (cr) {
Expand All @@ -115,7 +122,8 @@ rt_entry_free(struct ovs_router_entry *p)
free(p);
}

static void rt_init_match(struct match *match, const struct in6_addr *ip6_dst,
static void rt_init_match(struct match *match, uint32_t mark,
const struct in6_addr *ip6_dst,
uint8_t plen)
{
struct in6_addr dst;
Expand All @@ -127,6 +135,8 @@ static void rt_init_match(struct match *match, const struct in6_addr *ip6_dst,
memset(match, 0, sizeof *match);
match->flow.ipv6_dst = dst;
match->wc.masks.ipv6_dst = mask;
match->wc.masks.pkt_mark = UINT32_MAX;
match->flow.pkt_mark = mark;
}

static int
Expand Down Expand Up @@ -178,7 +188,8 @@ get_src_addr(const struct in6_addr *ip6_dst,
}

static int
ovs_router_insert__(uint8_t priority, const struct in6_addr *ip6_dst,
ovs_router_insert__(uint32_t mark, uint8_t priority,
const struct in6_addr *ip6_dst,
uint8_t plen, const char output_bridge[],
const struct in6_addr *gw)
{
Expand All @@ -187,13 +198,14 @@ ovs_router_insert__(uint8_t priority, const struct in6_addr *ip6_dst,
struct match match;
int err;

rt_init_match(&match, ip6_dst, plen);
rt_init_match(&match, mark, ip6_dst, plen);

p = xzalloc(sizeof *p);
ovs_strlcpy(p->output_bridge, output_bridge, sizeof p->output_bridge);
if (ipv6_addr_is_set(gw)) {
p->gw = *gw;
}
p->mark = mark;
p->nw_addr = match.flow.ipv6_dst;
p->plen = plen;
p->priority = priority;
Expand All @@ -202,7 +214,12 @@ ovs_router_insert__(uint8_t priority, const struct in6_addr *ip6_dst,
err = get_src_addr(gw, output_bridge, &p->src_addr);
}
if (err) {
struct ds ds = DS_EMPTY_INITIALIZER;

ipv6_format_mapped(ip6_dst, &ds);
VLOG_DBG_RL(&rl, "src addr not available for route %s", ds_cstr(&ds));
free(p);
ds_destroy(&ds);
return err;
}
/* Longest prefix matches first. */
Expand All @@ -222,13 +239,12 @@ ovs_router_insert__(uint8_t priority, const struct in6_addr *ip6_dst,
}

void
ovs_router_insert(const struct in6_addr *ip_dst, uint8_t plen,
ovs_router_insert(uint32_t mark, const struct in6_addr *ip_dst, uint8_t plen,
const char output_bridge[], const struct in6_addr *gw)
{
ovs_router_insert__(plen, ip_dst, plen, output_bridge, gw);
ovs_router_insert__(mark, plen, ip_dst, plen, output_bridge, gw);
}


static bool
__rt_entry_delete(const struct cls_rule *cr)
{
Expand All @@ -245,14 +261,15 @@ __rt_entry_delete(const struct cls_rule *cr)
}

static bool
rt_entry_delete(uint8_t priority, const struct in6_addr *ip6_dst, uint8_t plen)
rt_entry_delete(uint32_t mark, uint8_t priority,
const struct in6_addr *ip6_dst, uint8_t plen)
{
const struct cls_rule *cr;
struct cls_rule rule;
struct match match;
bool res = false;

rt_init_match(&match, ip6_dst, plen);
rt_init_match(&match, mark, ip6_dst, plen);

cls_rule_init(&rule, &match, priority);

Expand Down Expand Up @@ -292,32 +309,48 @@ static void
ovs_router_add(struct unixctl_conn *conn, int argc,
const char *argv[], void *aux OVS_UNUSED)
{
ovs_be32 ip;
unsigned int plen;
struct in6_addr gw6 = in6addr_any;
struct in6_addr ip6;
struct in6_addr gw6;
uint32_t mark = 0;
unsigned int plen;
ovs_be32 ip;
int err;

if (scan_ipv4_route(argv[1], &ip, &plen)) {
ovs_be32 gw = 0;
if (argc > 3 && !ip_parse(argv[3], &gw)) {
unixctl_command_reply_error(conn, "Invalid gateway");
return;

if (argc > 3) {
if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) &&
!ip_parse(argv[3], &gw)) {
unixctl_command_reply_error(conn, "Invalid pkt_mark or gateway");
return;
}
}
in6_addr_set_mapped_ipv4(&ip6, ip);
in6_addr_set_mapped_ipv4(&gw6, gw);
if (gw) {
in6_addr_set_mapped_ipv4(&gw6, gw);
}
plen += 96;
} else if (scan_ipv6_route(argv[1], &ip6, &plen)) {
gw6 = in6addr_any;
if (argc > 3 && !ipv6_parse(argv[3], &gw6)) {
unixctl_command_reply_error(conn, "Invalid IPv6 gateway");
return;
if (argc > 3) {
if (!ovs_scan(argv[3], "pkt_mark=%"SCNi32, &mark) &&
!ipv6_parse(argv[3], &gw6)) {
unixctl_command_reply_error(conn, "Invalid pkt_mark or IPv6 gateway");
return;
}
}
} else {
unixctl_command_reply_error(conn, "Invalid parameters");
return;
}
err = ovs_router_insert__(plen + 32, &ip6, plen, argv[2], &gw6);
if (argc > 4) {
if (!ovs_scan(argv[4], "pkt_mark=%"SCNi32, &mark)) {
unixctl_command_reply_error(conn, "Invalid pkt_mark");
return;
}
}

err = ovs_router_insert__(mark, plen + 32, &ip6, plen, argv[2], &gw6);
if (err) {
unixctl_command_reply_error(conn, "Error while inserting route.");
} else {
Expand All @@ -329,9 +362,10 @@ static void
ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED,
const char *argv[], void *aux OVS_UNUSED)
{
ovs_be32 ip;
unsigned int plen;
struct in6_addr ip6;
uint32_t mark = 0;
unsigned int plen;
ovs_be32 ip;

if (scan_ipv4_route(argv[1], &ip, &plen)) {
in6_addr_set_mapped_ipv4(&ip6, ip);
Expand All @@ -340,7 +374,14 @@ ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED,
unixctl_command_reply_error(conn, "Invalid parameters");
return;
}
if (rt_entry_delete(plen + 32, &ip6, plen)) {
if (argc > 2) {
if (!ovs_scan(argv[2], "pkt_mark=%"SCNi32, &mark)) {
unixctl_command_reply_error(conn, "Invalid pkt_mark");
return;
}
}

if (rt_entry_delete(mark, plen + 32, &ip6, plen)) {
unixctl_command_reply(conn, "OK");
seq_change(tnl_conf_seq);
} else {
Expand Down Expand Up @@ -368,7 +409,12 @@ ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
if (IN6_IS_ADDR_V4MAPPED(&rt->nw_addr)) {
plen -= 96;
}
ds_put_format(&ds, "/%"PRIu16" dev %s", plen, rt->output_bridge);
ds_put_format(&ds, "/%"PRIu16, plen);
if (rt->mark) {
ds_put_format(&ds, " MARK %"PRIu32, rt->mark);
}

ds_put_format(&ds, " dev %s", rt->output_bridge);
if (ipv6_addr_is_set(&rt->gw)) {
ds_put_format(&ds, " GW ");
ipv6_format_mapped(&rt->gw, &ds);
Expand All @@ -382,24 +428,31 @@ ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
}

static void
ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED,
ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc,
const char *argv[], void *aux OVS_UNUSED)
{
ovs_be32 ip;
struct in6_addr gw, src;
char iface[IFNAMSIZ];
struct in6_addr ip6;
unsigned int plen;
char iface[IFNAMSIZ];
struct in6_addr gw, src;
uint32_t mark = 0;
ovs_be32 ip;

if (scan_ipv4_route(argv[1], &ip, &plen) && plen == 32) {
in6_addr_set_mapped_ipv4(&ip6, ip);
} else if (!(scan_ipv6_route(argv[1], &ip6, &plen) && plen == 128)) {
unixctl_command_reply_error(conn, "Invalid parameters");
return;
}

if (ovs_router_lookup(&ip6, iface, &src, &gw)) {
if (argc > 2) {
if (!ovs_scan(argv[2], "pkt_mark=%"SCNi32, &mark)) {
unixctl_command_reply_error(conn, "Invalid pkt_mark");
return;
}
}
if (ovs_router_lookup(mark, &ip6, iface, &src, &gw)) {
struct ds ds = DS_EMPTY_INITIALIZER;

ds_put_format(&ds, "src ");
ipv6_format_mapped(&src, &ds);
ds_put_format(&ds, "\ngateway ");
Expand Down Expand Up @@ -434,11 +487,11 @@ void
ovs_router_init(void)
{
classifier_init(&cls, NULL);
unixctl_command_register("ovs/route/add", "ip_addr/prefix_len out_br_name gw", 2, 3,
unixctl_command_register("ovs/route/add", "ip_addr/prefix_len out_br_name [gw] [pkt_mark=mark]", 2, 4,
ovs_router_add, NULL);
unixctl_command_register("ovs/route/show", "", 0, 0, ovs_router_show, NULL);
unixctl_command_register("ovs/route/del", "ip_addr/prefix_len", 1, 1, ovs_router_del,
NULL);
unixctl_command_register("ovs/route/lookup", "ip_addr", 1, 1,
unixctl_command_register("ovs/route/del", "ip_addr/prefix_len [pkt_mark=mark]", 1, 2,
ovs_router_del, NULL);
unixctl_command_register("ovs/route/lookup", "ip_addr [pkt_mark=mark]", 1, 2,
ovs_router_lookup_cmd, NULL);
}
6 changes: 4 additions & 2 deletions lib/ovs-router.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
extern "C" {
#endif

bool ovs_router_lookup(const struct in6_addr *ip_dst, char out_dev[],
bool ovs_router_lookup(uint32_t mark, const struct in6_addr *ip_dst,
char out_dev[],
struct in6_addr *src, struct in6_addr *gw);
void ovs_router_init(void);
void ovs_router_insert(const struct in6_addr *ip_dst, uint8_t plen,
void ovs_router_insert(uint32_t mark, const struct in6_addr *ip_dst,
uint8_t plen,
const char output_bridge[], const struct in6_addr *gw);
void ovs_router_flush(void);
#ifdef __cplusplus
Expand Down
2 changes: 1 addition & 1 deletion lib/route-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ route_table_handle_msg(const struct route_table_msg *change)
if (change->relevant && change->nlmsg_type == RTM_NEWROUTE) {
const struct route_data *rd = &change->rd;

ovs_router_insert(&rd->rta_dst, rd->rtm_dst_len,
ovs_router_insert(rd->mark, &rd->rta_dst, rd->rtm_dst_len,
rd->ifname, &rd->rta_gw);
}
}
Expand Down
5 changes: 4 additions & 1 deletion ofproto/ofproto-dpif-sflow.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,10 @@ sflow_choose_agent_address(const char *agent_device,
struct in6_addr addr6, src, gw;

in6_addr_set_mapped_ipv4(&addr6, sa.sin.sin_addr.s_addr);
if (ovs_router_lookup(&addr6, name, &src, &gw)) {
/* sFlow only supports target in default routing table with
* packet mark zero.
*/
if (ovs_router_lookup(0, &addr6, name, &src, &gw)) {

in4.s_addr = in6_addr_get_mapped_ipv4(&src);
goto success;
Expand Down
2 changes: 1 addition & 1 deletion ofproto/ofproto-dpif-xlate.c
Original file line number Diff line number Diff line change
Expand Up @@ -2878,7 +2878,7 @@ tnl_route_lookup_flow(const struct flow *oflow,
struct in6_addr dst;

dst = flow_tnl_dst(&oflow->tunnel);
if (!ovs_router_lookup(&dst, out_dev, src, &gw)) {
if (!ovs_router_lookup(oflow->pkt_mark, &dst, out_dev, src, &gw)) {
return -ENOENT;
}

Expand Down
Loading

0 comments on commit ed52ca5

Please sign in to comment.