Coverage Report

Created: 2025-10-13 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openvswitch/lib/route-table.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2011, 2012, 2013, 2014, 2017 Nicira, Inc.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at:
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include <config.h>
18
19
#include "route-table.h"
20
21
#include <errno.h>
22
#include <sys/types.h>
23
#include <netinet/in.h>
24
#include <arpa/inet.h>
25
#include <sys/socket.h>
26
#include <linux/rtnetlink.h>
27
#include <net/if.h>
28
29
#include "coverage.h"
30
#include "hash.h"
31
#include "netdev.h"
32
#include "netlink.h"
33
#include "netlink-notifier.h"
34
#include "netlink-socket.h"
35
#include "openvswitch/list.h"
36
#include "openvswitch/ofpbuf.h"
37
#include "ovs-router.h"
38
#include "packets.h"
39
#include "rtnetlink.h"
40
#include "tnl-ports.h"
41
#include "openvswitch/vlog.h"
42
43
/* Linux 2.6.36 added RTA_MARK, so define it just in case we're building with
44
 * old headers.  (We can't test for it with #ifdef because it's an enum.) */
45
0
#define RTA_MARK 16
46
47
/* Linux 4.1 added RTA_VIA. */
48
#ifndef HAVE_RTA_VIA
49
#define RTA_VIA 18
50
struct rtvia {
51
    sa_family_t rtvia_family;
52
    uint8_t     rtvia_addr[];
53
};
54
#endif
55
56
VLOG_DEFINE_THIS_MODULE(route_table);
57
58
COVERAGE_DEFINE(route_table_dump);
59
60
static struct ovs_mutex route_table_mutex = OVS_MUTEX_INITIALIZER;
61
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
62
63
/* Global change number for route-table, which should be incremented
64
 * every time route_table_reset() is called.  */
65
static uint64_t rt_change_seq;
66
67
static struct nln *nln = NULL;
68
static struct route_table_msg nln_rtmsg_change;
69
static struct nln_notifier *route_notifier = NULL;
70
static struct nln_notifier *route6_notifier = NULL;
71
static struct nln_notifier *name_notifier = NULL;
72
73
static bool route_table_valid = false;
74
75
static void route_table_reset(void);
76
static void route_table_handle_msg(const struct route_table_msg *, void *aux);
77
static void route_table_change(struct route_table_msg *, void *aux);
78
static void route_map_clear(void);
79
80
static void name_table_init(void);
81
static void name_table_change(const struct rtnetlink_change *, void *);
82
83
static void
84
route_data_destroy_nexthops__(struct route_data *rd)
85
0
{
86
0
    struct route_data_nexthop *rdnh;
87
88
0
    LIST_FOR_EACH_POP (rdnh, nexthop_node, &rd->nexthops) {
89
0
        if (rdnh && rdnh != &rd->primary_next_hop__) {
90
0
            free(rdnh);
91
0
        }
92
0
    }
93
0
}
94
95
void
96
route_data_destroy(struct route_data *rd)
97
0
{
98
0
    route_data_destroy_nexthops__(rd);
99
0
}
100
101
uint64_t
102
route_table_get_change_seq(void)
103
0
{
104
0
    return rt_change_seq;
105
0
}
106
107
/* Users of the route_table module should register themselves with this
108
 * function before making any other route_table function calls. */
109
void
110
route_table_init(void)
111
    OVS_EXCLUDED(route_table_mutex)
112
0
{
113
0
    ovs_mutex_lock(&route_table_mutex);
114
0
    ovs_assert(!nln);
115
0
    ovs_assert(!route_notifier);
116
0
    ovs_assert(!route6_notifier);
117
118
0
    ovs_router_init();
119
0
    nln = nln_create(NETLINK_ROUTE, route_table_parse, &nln_rtmsg_change);
120
121
0
    route_notifier =
122
0
        nln_notifier_create(nln, RTNLGRP_IPV4_ROUTE,
123
0
                            (nln_notify_func *) route_table_change, NULL);
124
0
    route6_notifier =
125
0
        nln_notifier_create(nln, RTNLGRP_IPV6_ROUTE,
126
0
                            (nln_notify_func *) route_table_change, NULL);
127
128
0
    route_table_reset();
129
0
    name_table_init();
130
131
0
    ovs_mutex_unlock(&route_table_mutex);
132
0
}
133
134
/* Run periodically to update the locally maintained routing table. */
135
void
136
route_table_run(void)
137
    OVS_EXCLUDED(route_table_mutex)
138
0
{
139
0
    ovs_mutex_lock(&route_table_mutex);
140
0
    if (nln) {
141
0
        rtnetlink_run();
142
0
        nln_run(nln);
143
144
0
        if (!route_table_valid) {
145
0
            route_table_reset();
146
0
        }
147
0
    }
148
0
    ovs_mutex_unlock(&route_table_mutex);
149
0
}
150
151
/* Causes poll_block() to wake up when route_table updates are required. */
152
void
153
route_table_wait(void)
154
    OVS_EXCLUDED(route_table_mutex)
155
0
{
156
0
    ovs_mutex_lock(&route_table_mutex);
157
0
    if (nln) {
158
0
        rtnetlink_wait();
159
0
        nln_wait(nln);
160
0
    }
161
0
    ovs_mutex_unlock(&route_table_mutex);
162
0
}
163
164
bool
165
route_table_dump_one_table(uint32_t id,
166
                           route_table_handle_msg_callback *handle_msg_cb,
167
                           void *aux)
168
0
{
169
0
    uint64_t reply_stub[NL_DUMP_BUFSIZE / 8];
170
0
    struct ofpbuf request, reply, buf;
171
0
    struct rtmsg *rq_msg;
172
0
    bool filtered = true;
173
0
    struct nl_dump dump;
174
175
0
    ofpbuf_init(&request, 0);
176
177
0
    nl_msg_put_nlmsghdr(&request, sizeof *rq_msg, RTM_GETROUTE, NLM_F_REQUEST);
178
179
0
    rq_msg = ofpbuf_put_zeros(&request, sizeof *rq_msg);
180
0
    rq_msg->rtm_family = AF_UNSPEC;
181
182
0
    if (id > UCHAR_MAX) {
183
0
        rq_msg->rtm_table = RT_TABLE_UNSPEC;
184
0
        nl_msg_put_u32(&request, RTA_TABLE, id);
185
0
    } else {
186
0
        rq_msg->rtm_table = id;
187
0
    }
188
189
0
    nl_dump_start(&dump, NETLINK_ROUTE, &request);
190
0
    ofpbuf_uninit(&request);
191
192
0
    ofpbuf_use_stub(&buf, reply_stub, sizeof reply_stub);
193
0
    while (nl_dump_next(&dump, &reply, &buf)) {
194
0
        struct route_table_msg msg;
195
196
0
        if (route_table_parse(&reply, &msg)) {
197
0
            struct nlmsghdr *nlmsghdr = nl_msg_nlmsghdr(&reply);
198
199
            /* Older kernels do not support filtering. */
200
0
            if (!(nlmsghdr->nlmsg_flags & NLM_F_DUMP_FILTERED)) {
201
0
                filtered = false;
202
0
            }
203
0
            handle_msg_cb(&msg, aux);
204
0
            route_data_destroy(&msg.rd);
205
0
        }
206
0
    }
207
0
    ofpbuf_uninit(&buf);
208
0
    nl_dump_done(&dump);
209
210
0
    return filtered;
211
0
}
212
213
static void
214
route_table_reset(void)
215
0
{
216
0
    uint32_t tables[] = {
217
0
        RT_TABLE_DEFAULT,
218
0
        RT_TABLE_MAIN,
219
0
        RT_TABLE_LOCAL,
220
0
    };
221
222
0
    route_map_clear();
223
0
    netdev_get_addrs_list_flush();
224
0
    route_table_valid = true;
225
0
    rt_change_seq++;
226
227
0
    COVERAGE_INC(route_table_dump);
228
229
0
    for (size_t i = 0; i < ARRAY_SIZE(tables); i++) {
230
0
        if (!route_table_dump_one_table(tables[i],
231
0
                                        route_table_handle_msg, NULL)) {
232
            /* Got unfiltered reply, no need to dump further. */
233
0
            break;
234
0
        }
235
0
    }
236
0
}
237
238
/* Returns true if the given route requires nexthop information (output
239
 * interface, nexthop IP, ...).  Returns false for special route types
240
 * that don't need this information. */
241
static bool
242
route_type_needs_nexthop(unsigned char rtmsg_type)
243
0
{
244
0
    switch (rtmsg_type) {
245
0
    case RTN_BLACKHOLE:
246
0
    case RTN_THROW:
247
0
    case RTN_UNREACHABLE:
248
0
    case RTN_PROHIBIT:
249
0
        return false;
250
251
0
    default:
252
0
        return true;
253
0
    }
254
0
}
255
256
static int
257
route_table_parse__(struct ofpbuf *buf, size_t ofs,
258
                    const struct nlmsghdr *nlmsg,
259
                    const struct rtmsg *rtm,
260
                    const struct rtnexthop *rtnh,
261
                    struct route_table_msg *change)
262
0
{
263
0
    bool parsed, ipv4 = false;
264
265
0
    static const struct nl_policy policy[] = {
266
0
        [RTA_DST] = { .type = NL_A_U32, .optional = true  },
267
0
        [RTA_OIF] = { .type = NL_A_U32, .optional = true },
268
0
        [RTA_GATEWAY] = { .type = NL_A_U32, .optional = true },
269
0
        [RTA_MARK] = { .type = NL_A_U32, .optional = true },
270
0
        [RTA_PREFSRC] = { .type = NL_A_U32, .optional = true },
271
0
        [RTA_TABLE] = { .type = NL_A_U32, .optional = true },
272
0
        [RTA_PRIORITY] = { .type = NL_A_U32, .optional = true },
273
0
        [RTA_VIA] = { .type = NL_A_RTA_VIA, .optional = true },
274
0
        [RTA_MULTIPATH] = { .type = NL_A_NESTED, .optional = true },
275
0
    };
276
277
0
    static const struct nl_policy policy6[] = {
278
0
        [RTA_DST] = { .type = NL_A_IPV6, .optional = true },
279
0
        [RTA_OIF] = { .type = NL_A_U32, .optional = true },
280
0
        [RTA_MARK] = { .type = NL_A_U32, .optional = true },
281
0
        [RTA_GATEWAY] = { .type = NL_A_IPV6, .optional = true },
282
0
        [RTA_PREFSRC] = { .type = NL_A_IPV6, .optional = true },
283
0
        [RTA_TABLE] = { .type = NL_A_U32, .optional = true },
284
0
        [RTA_PRIORITY] = { .type = NL_A_U32, .optional = true },
285
0
        [RTA_VIA] = { .type = NL_A_RTA_VIA, .optional = true },
286
0
        [RTA_MULTIPATH] = { .type = NL_A_NESTED, .optional = true },
287
0
    };
288
289
0
    struct nlattr *attrs[ARRAY_SIZE(policy)];
290
291
0
    if (rtm->rtm_family == AF_INET) {
292
0
        parsed = nl_policy_parse(buf, ofs, policy, attrs,
293
0
                                 ARRAY_SIZE(policy));
294
0
        ipv4 = true;
295
0
    } else if (rtm->rtm_family == AF_INET6) {
296
0
        parsed = nl_policy_parse(buf, ofs, policy6, attrs,
297
0
                                 ARRAY_SIZE(policy6));
298
0
    } else {
299
0
        VLOG_DBG_RL(&rl, "received non AF_INET rtnetlink route message");
300
0
        return 0;
301
0
    }
302
303
0
    if (parsed) {
304
0
        struct route_data_nexthop *rdnh = NULL;
305
0
        int rta_oif;      /* Output interface index. */
306
307
0
        memset(change, 0, sizeof *change);
308
309
0
        ovs_list_init(&change->rd.nexthops);
310
0
        rdnh = rtnh ? xzalloc(sizeof *rdnh) : &change->rd.primary_next_hop__;
311
0
        ovs_list_insert(&change->rd.nexthops, &rdnh->nexthop_node);
312
313
0
        rdnh->family = rtm->rtm_family;
314
0
        change->relevant = true;
315
316
0
        if (rtm->rtm_scope == RT_SCOPE_NOWHERE) {
317
0
            change->relevant = false;
318
0
        }
319
320
0
        if (rtm->rtm_type != RTN_UNICAST &&
321
0
            rtm->rtm_type != RTN_LOCAL) {
322
0
            change->relevant = false;
323
0
        }
324
325
0
        change->rd.rta_table_id = rtm->rtm_table;
326
0
        if (attrs[RTA_TABLE]) {
327
0
            change->rd.rta_table_id = nl_attr_get_u32(attrs[RTA_TABLE]);
328
0
        }
329
330
0
        change->nlmsg_type     = nlmsg->nlmsg_type;
331
0
        change->rd.rtm_dst_len = rtm->rtm_dst_len;
332
0
        change->rd.rtm_protocol = rtm->rtm_protocol;
333
0
        change->rd.rtn_local = rtm->rtm_type == RTN_LOCAL;
334
0
        if (attrs[RTA_OIF] && rtnh) {
335
0
            VLOG_DBG_RL(&rl, "unexpected RTA_OIF attribute while parsing "
336
0
                             "nested RTA_MULTIPATH attributes");
337
0
            goto error_out;
338
0
        }
339
0
        if (attrs[RTA_OIF] || rtnh) {
340
0
            rta_oif = rtnh ? rtnh->rtnh_ifindex
341
0
                           : nl_attr_get_u32(attrs[RTA_OIF]);
342
343
0
            if (!if_indextoname(rta_oif, rdnh->ifname)) {
344
0
                int error = errno;
345
346
0
                VLOG_DBG_RL(&rl, "could not find interface name[%u]: %s",
347
0
                            rta_oif, ovs_strerror(error));
348
0
                if (error == ENXIO) {
349
0
                    change->relevant = false;
350
0
                } else {
351
0
                    goto error_out;
352
0
                }
353
0
            }
354
0
        }
355
356
0
        if (attrs[RTA_DST]) {
357
0
            if (ipv4) {
358
0
                ovs_be32 dst;
359
0
                dst = nl_attr_get_be32(attrs[RTA_DST]);
360
0
                in6_addr_set_mapped_ipv4(&change->rd.rta_dst, dst);
361
0
            } else {
362
0
                change->rd.rta_dst = nl_attr_get_in6_addr(attrs[RTA_DST]);
363
0
            }
364
0
        } else if (ipv4) {
365
0
            in6_addr_set_mapped_ipv4(&change->rd.rta_dst, 0);
366
0
        }
367
0
        if (attrs[RTA_PREFSRC]) {
368
0
            if (ipv4) {
369
0
                ovs_be32 prefsrc;
370
0
                prefsrc = nl_attr_get_be32(attrs[RTA_PREFSRC]);
371
0
                in6_addr_set_mapped_ipv4(&change->rd.rta_prefsrc, prefsrc);
372
0
            } else {
373
0
                change->rd.rta_prefsrc =
374
0
                    nl_attr_get_in6_addr(attrs[RTA_PREFSRC]);
375
0
            }
376
0
        }
377
0
        if (attrs[RTA_GATEWAY]) {
378
0
            if (ipv4) {
379
0
                ovs_be32 gw;
380
0
                gw = nl_attr_get_be32(attrs[RTA_GATEWAY]);
381
0
                in6_addr_set_mapped_ipv4(&rdnh->addr, gw);
382
0
            } else {
383
0
                rdnh->addr = nl_attr_get_in6_addr(attrs[RTA_GATEWAY]);
384
0
            }
385
0
        }
386
0
        if (attrs[RTA_MARK]) {
387
0
            change->rd.rta_mark = nl_attr_get_u32(attrs[RTA_MARK]);
388
0
        }
389
0
        if (attrs[RTA_PRIORITY]) {
390
0
            change->rd.rta_priority = nl_attr_get_u32(attrs[RTA_PRIORITY]);
391
0
        }
392
0
        if (attrs[RTA_VIA]) {
393
0
            const struct rtvia *rtvia = nl_attr_get(attrs[RTA_VIA]);
394
0
            ovs_be32 addr;
395
396
0
            if (attrs[RTA_GATEWAY]) {
397
0
                VLOG_DBG_RL(&rl, "route message can not contain both "
398
0
                                 "RTA_GATEWAY and RTA_VIA");
399
0
                goto error_out;
400
0
            }
401
402
0
            rdnh->family = rtvia->rtvia_family;
403
404
0
            switch (rdnh->family) {
405
0
            case AF_INET:
406
0
                if (nl_attr_get_size(attrs[RTA_VIA])
407
0
                        - sizeof *rtvia < sizeof addr) {
408
0
                    VLOG_DBG_RL(&rl, "got short message while parsing RTA_VIA "
409
0
                                     "attribute for family AF_INET");
410
0
                    goto error_out;
411
0
                }
412
0
                memcpy(&addr, rtvia->rtvia_addr, sizeof addr);
413
0
                in6_addr_set_mapped_ipv4(&rdnh->addr, addr);
414
0
                break;
415
416
0
            case AF_INET6:
417
0
                if (nl_attr_get_size(attrs[RTA_VIA])
418
0
                        - sizeof *rtvia < sizeof rdnh->addr) {
419
0
                    VLOG_DBG_RL(&rl, "got short message while parsing RTA_VIA "
420
0
                                     "attribute for family AF_INET6");
421
0
                    goto error_out;
422
0
                }
423
0
                memcpy(&rdnh->addr, rtvia->rtvia_addr, sizeof rdnh->addr);
424
0
                break;
425
426
0
            default:
427
0
                VLOG_DBG_RL(&rl, "unsupported address family, %d, "
428
0
                                 "in via attribute", rdnh->family);
429
0
                goto error_out;
430
0
            }
431
0
        }
432
0
        if (attrs[RTA_MULTIPATH]) {
433
0
            const struct nlattr *nla;
434
0
            size_t left;
435
436
0
            if (rtnh) {
437
0
                VLOG_DBG_RL(&rl, "unexpected nested RTA_MULTIPATH attribute");
438
0
                goto error_out;
439
0
            }
440
441
            /* The change->rd->nexthops list is unconditionally populated with
442
             * a single rdnh entry as we start parsing above.  Multiple
443
             * branches above may access it or jump to error_out, and having it
444
             * on the list is the only way to ensure proper cleanup.
445
             *
446
             * Getting to this point, we know that the above branches has not
447
             * provided next hop information, because information about
448
             * multiple next hops is encoded in the nested attributes after the
449
             * RTA_MULTIPATH attribute.
450
             *
451
             * Before retrieving those we need to remove the empty rdnh entry
452
             * from the list. */
453
0
            route_data_destroy_nexthops__(&change->rd);
454
455
0
            NL_NESTED_FOR_EACH (nla, left, attrs[RTA_MULTIPATH]) {
456
0
                struct route_table_msg mp_change;
457
0
                struct rtnexthop *mp_rtnh;
458
0
                struct ofpbuf mp_buf;
459
460
0
                ofpbuf_use_const(&mp_buf, nla, nla->nla_len);
461
0
                mp_rtnh = ofpbuf_try_pull(&mp_buf, sizeof *mp_rtnh);
462
463
0
                if (!mp_rtnh) {
464
0
                    VLOG_DBG_RL(&rl, "got short message while parsing "
465
0
                                     "multipath attribute");
466
0
                    goto error_out;
467
0
                }
468
469
0
                if (!route_table_parse__(&mp_buf, 0, nlmsg, rtm, mp_rtnh,
470
0
                                         &mp_change)) {
471
0
                    goto error_out;
472
0
                }
473
0
                ovs_list_push_back_all(&change->rd.nexthops,
474
0
                                       &mp_change.rd.nexthops);
475
0
            }
476
0
        }
477
0
        if (route_type_needs_nexthop(rtm->rtm_type)
478
0
            && !attrs[RTA_OIF] && !attrs[RTA_GATEWAY]
479
0
            && !attrs[RTA_VIA] && !attrs[RTA_MULTIPATH]) {
480
0
            VLOG_DBG_RL(&rl, "route message needs an RTA_OIF, RTA_GATEWAY, "
481
0
                             "RTA_VIA or RTA_MULTIPATH attribute");
482
0
            goto error_out;
483
0
        }
484
        /* Add any additional RTA attribute processing before RTA_MULTIPATH. */
485
486
        /* Ensure that the change->rd->nexthops list is cleared in cases when
487
         * the route does not need a next hop. */
488
0
        if (!route_type_needs_nexthop(rtm->rtm_type)) {
489
0
            route_data_destroy_nexthops__(&change->rd);
490
0
        }
491
0
    } else {
492
0
        VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message");
493
0
        goto error_out;
494
0
    }
495
496
    /* Success. */
497
0
    return ipv4 ? RTNLGRP_IPV4_ROUTE : RTNLGRP_IPV6_ROUTE;
498
499
0
error_out:
500
0
    route_data_destroy(&change->rd);
501
0
    return 0;
502
0
}
503
504
/* Parse Netlink message in buf, which is expected to contain a UAPI rtmsg
505
 * header and associated route attributes.
506
 *
507
 * Return RTNLGRP_IPV4_ROUTE or RTNLGRP_IPV6_ROUTE on success, and 0 on a parse
508
 * error.
509
 *
510
 * On success, memory may have been allocated, and it is the caller's
511
 * responsibility to free it with a call to route_data_destroy().
512
 *
513
 * In case of error, any allocated memory will be freed before returning. */
514
int
515
route_table_parse(struct ofpbuf *buf, void *change)
516
0
{
517
0
    struct nlmsghdr *nlmsg;
518
0
    struct rtmsg *rtm;
519
520
0
    nlmsg = ofpbuf_at(buf, 0, NLMSG_HDRLEN);
521
0
    rtm = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *rtm);
522
523
0
    if (!nlmsg || !rtm) {
524
0
        return 0;
525
0
    }
526
527
0
    return route_table_parse__(buf, NLMSG_HDRLEN + sizeof *rtm,
528
0
                               nlmsg, rtm, NULL, change);
529
0
}
530
531
static bool
532
is_standard_table_id(uint32_t table_id)
533
0
{
534
0
    return !table_id
535
0
           || table_id == RT_TABLE_DEFAULT
536
0
           || table_id == RT_TABLE_MAIN
537
0
           || table_id == RT_TABLE_LOCAL;
538
0
}
539
540
static void
541
route_table_change(struct route_table_msg *change, void *aux OVS_UNUSED)
542
0
{
543
0
    if (!change
544
0
        || (change->relevant
545
0
            && is_standard_table_id(change->rd.rta_table_id))) {
546
0
        route_table_valid = false;
547
0
    }
548
0
    if (change) {
549
0
        route_data_destroy(&change->rd);
550
0
    }
551
0
}
552
553
static void
554
route_table_handle_msg(const struct route_table_msg *change,
555
                       void *aux OVS_UNUSED)
556
0
{
557
0
    if (change->relevant && change->nlmsg_type == RTM_NEWROUTE
558
0
            && !ovs_list_is_empty(&change->rd.nexthops)) {
559
0
        const struct route_data *rd = &change->rd;
560
0
        const struct route_data_nexthop *rdnh;
561
562
        /* The ovs-router module currently does not implement lookup or
563
         * storage for routes with multiple next hops.  For backwards
564
         * compatibility, we use the first next hop. */
565
0
        rdnh = CONTAINER_OF(ovs_list_front(&change->rd.nexthops),
566
0
                            const struct route_data_nexthop, nexthop_node);
567
568
0
        ovs_router_insert(rd->rta_mark, &rd->rta_dst,
569
0
                          IN6_IS_ADDR_V4MAPPED(&rd->rta_dst)
570
0
                          ? rd->rtm_dst_len + 96 : rd->rtm_dst_len,
571
0
                          rd->rtn_local, rdnh->ifname, &rdnh->addr,
572
0
                          &rd->rta_prefsrc);
573
0
    }
574
0
}
575
576
static void
577
route_map_clear(void)
578
0
{
579
0
    ovs_router_flush();
580
0
}
581
582
bool
583
route_table_fallback_lookup(const struct in6_addr *ip6_dst OVS_UNUSED,
584
                            char name[] OVS_UNUSED,
585
                            struct in6_addr *gw6)
586
0
{
587
0
    *gw6 = in6addr_any;
588
0
    return false;
589
0
}
590
591

592
/* name_table . */
593
594
static void
595
name_table_init(void)
596
0
{
597
0
    name_notifier = rtnetlink_notifier_create(name_table_change, NULL);
598
0
}
599
600
601
static void
602
name_table_change(const struct rtnetlink_change *change,
603
                  void *aux OVS_UNUSED)
604
0
{
605
0
    if (change && change->irrelevant) {
606
0
        return;
607
0
    }
608
609
    /* Changes to interface status can cause routing table changes that some
610
     * versions of the linux kernel do not advertise for some reason. */
611
0
    route_table_valid = false;
612
613
0
    if (change && change->nlmsg_type == RTM_DELLINK) {
614
0
        if (change->ifname) {
615
0
            tnl_port_map_delete_ipdev(change->ifname);
616
0
        }
617
0
    }
618
0
}