/* A digested version of a route message sent down by the kernel to indicate
* that a route has changed. */
struct route_table_msg {
+ bool relevant; /* Should this message be processed? */
int nlmsg_type; /* e.g. RTM_NEWROUTE, RTM_DELROUTE. */
struct route_data rd; /* Data parsed from this message. */
};
static struct rtnetlink *rtn = NULL;
static struct route_table_msg rtmsg;
static struct rtnetlink_notifier notifier;
+
+static bool route_table_valid = false;
static struct hmap route_map;
static int route_table_reset(void);
+static void route_table_handle_msg(const struct route_table_msg *);
static bool route_table_parse(struct ofpbuf *, struct route_table_msg *);
static void route_table_change(const struct route_table_msg *, void *);
static struct route_node *route_node_lookup(const struct route_data *);
*ifindex = 0;
+ if (!route_table_valid) {
+ route_table_reset();
+ }
+
rn = route_node_lookup_by_ip(ip);
if (rn) {
static struct nl_sock *rtnl_sock;
route_map_clear();
+ route_table_valid = true;
error = nl_sock_create(NETLINK_ROUTE, 0, 0, 0, &rtnl_sock);
if (error) {
struct route_table_msg msg;
if (route_table_parse(&reply, &msg)) {
- route_table_change(&msg, NULL);
+ route_table_handle_msg(&msg);
}
}
}
memset(change, 0, sizeof *change);
+ change->relevant = true;
+
+ if (rtm->rtm_scope == RT_SCOPE_NOWHERE) {
+ change->relevant = false;
+ }
+
+ if (rtm->rtm_type != RTN_UNICAST &&
+ rtm->rtm_type != RTN_LOCAL) {
+ change->relevant = false;
+ }
change->nlmsg_type = nlmsg->nlmsg_type;
change->rd.rtm_dst_len = rtm->rtm_dst_len;
}
static void
-route_table_change(const struct route_table_msg *change, void *aux OVS_UNUSED)
+route_table_change(const struct route_table_msg *change OVS_UNUSED,
+ void *aux OVS_UNUSED)
{
- if (!change) {
- VLOG_DBG_RL(&rl, "received NULL change message");
- route_table_reset();
- } else if (change->nlmsg_type == RTM_NEWROUTE) {
- if (!route_node_lookup(&change->rd)) {
- struct route_node *rn;
-
- rn = xzalloc(sizeof *rn);
- memcpy(&rn->rd, &change->rd, sizeof change->rd);
+ route_table_valid = false;
+}
- hmap_insert(&route_map, &rn->node, hash_route_data(&rn->rd));
- } else {
- VLOG_DBG_RL(&rl, "skipping insertion of duplicate route entry");
- }
- } else if (change->nlmsg_type == RTM_DELROUTE) {
+static void
+route_table_handle_msg(const struct route_table_msg *change)
+{
+ if (change->relevant && change->nlmsg_type == RTM_NEWROUTE &&
+ !route_node_lookup(&change->rd)) {
struct route_node *rn;
- rn = route_node_lookup(&change->rd);
+ rn = xzalloc(sizeof *rn);
+ memcpy(&rn->rd, &change->rd, sizeof change->rd);
- if (rn) {
- hmap_remove(&route_map, &rn->node);
- free(rn);
- } else {
- VLOG_DBG_RL(&rl, "skipping deletion of non-existent route entry");
- }
+ hmap_insert(&route_map, &rn->node, hash_route_data(&rn->rd));
}
}