1 /* SPDX-License-Identifier: LGPL-2.1-or-later
2 * Copyright © 2019 VMware, Inc.
5 #include <linux/nexthop.h>
7 #include "alloc-util.h"
8 #include "netlink-util.h"
9 #include "networkd-link.h"
10 #include "networkd-manager.h"
11 #include "networkd-network.h"
12 #include "networkd-nexthop.h"
13 #include "networkd-queue.h"
14 #include "networkd-route.h"
15 #include "parse-util.h"
17 #include "string-util.h"
19 NextHop
*nexthop_free(NextHop
*nexthop
) {
23 if (nexthop
->network
) {
24 assert(nexthop
->section
);
25 hashmap_remove(nexthop
->network
->nexthops_by_section
, nexthop
->section
);
28 network_config_section_free(nexthop
->section
);
31 set_remove(nexthop
->link
->nexthops
, nexthop
);
32 set_remove(nexthop
->link
->nexthops_foreign
, nexthop
);
34 if (nexthop
->link
->manager
&& nexthop
->id
> 0)
35 hashmap_remove(nexthop
->link
->manager
->nexthops_by_id
, UINT32_TO_PTR(nexthop
->id
));
38 if (nexthop
->manager
) {
39 set_remove(nexthop
->manager
->nexthops
, nexthop
);
40 set_remove(nexthop
->manager
->nexthops_foreign
, nexthop
);
43 hashmap_remove(nexthop
->manager
->nexthops_by_id
, UINT32_TO_PTR(nexthop
->id
));
46 return mfree(nexthop
);
49 DEFINE_NETWORK_SECTION_FUNCTIONS(NextHop
, nexthop_free
);
51 static int nexthop_new(NextHop
**ret
) {
52 _cleanup_(nexthop_freep
) NextHop
*nexthop
= NULL
;
54 nexthop
= new(NextHop
, 1);
58 *nexthop
= (NextHop
) {
63 *ret
= TAKE_PTR(nexthop
);
68 static int nexthop_new_static(Network
*network
, const char *filename
, unsigned section_line
, NextHop
**ret
) {
69 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
70 _cleanup_(nexthop_freep
) NextHop
*nexthop
= NULL
;
76 assert(section_line
> 0);
78 r
= network_config_section_new(filename
, section_line
, &n
);
82 nexthop
= hashmap_get(network
->nexthops_by_section
, n
);
84 *ret
= TAKE_PTR(nexthop
);
88 r
= nexthop_new(&nexthop
);
92 nexthop
->protocol
= RTPROT_STATIC
;
93 nexthop
->network
= network
;
94 nexthop
->section
= TAKE_PTR(n
);
96 r
= hashmap_ensure_put(&network
->nexthops_by_section
, &network_config_hash_ops
, nexthop
->section
, nexthop
);
100 *ret
= TAKE_PTR(nexthop
);
104 static void nexthop_hash_func(const NextHop
*nexthop
, struct siphash
*state
) {
107 siphash24_compress(&nexthop
->protocol
, sizeof(nexthop
->protocol
), state
);
108 siphash24_compress(&nexthop
->id
, sizeof(nexthop
->id
), state
);
109 siphash24_compress(&nexthop
->blackhole
, sizeof(nexthop
->blackhole
), state
);
110 siphash24_compress(&nexthop
->family
, sizeof(nexthop
->family
), state
);
112 switch (nexthop
->family
) {
115 siphash24_compress(&nexthop
->gw
, FAMILY_ADDRESS_SIZE(nexthop
->family
), state
);
119 /* treat any other address family as AF_UNSPEC */
124 static int nexthop_compare_func(const NextHop
*a
, const NextHop
*b
) {
127 r
= CMP(a
->protocol
, b
->protocol
);
131 r
= CMP(a
->id
, b
->id
);
135 r
= CMP(a
->blackhole
, b
->blackhole
);
139 r
= CMP(a
->family
, b
->family
);
143 if (IN_SET(a
->family
, AF_INET
, AF_INET6
))
144 return memcmp(&a
->gw
, &b
->gw
, FAMILY_ADDRESS_SIZE(a
->family
));
149 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
153 nexthop_compare_func
,
156 static bool nexthop_equal(const NextHop
*a
, const NextHop
*b
) {
163 return nexthop_compare_func(a
, b
) == 0;
166 static void nexthop_copy(NextHop
*dest
, const NextHop
*src
) {
170 /* This only copies entries used in the above hash and compare functions. */
172 dest
->protocol
= src
->protocol
;
174 dest
->blackhole
= src
->blackhole
;
175 dest
->family
= src
->family
;
179 int manager_get_nexthop_by_id(Manager
*manager
, uint32_t id
, NextHop
**ret
) {
187 nh
= hashmap_get(manager
->nexthops_by_id
, UINT32_TO_PTR(id
));
196 static int nexthop_get(Manager
*manager
, Link
*link
, const NextHop
*in
, NextHop
**ret
) {
199 assert(manager
|| link
);
202 existing
= set_get(link
? link
->nexthops
: manager
->nexthops
, in
);
209 existing
= set_get(link
? link
->nexthops_foreign
: manager
->nexthops_foreign
, in
);
219 static int nexthop_add_internal(Manager
*manager
, Link
*link
, Set
**nexthops
, const NextHop
*in
, NextHop
**ret
) {
220 _cleanup_(nexthop_freep
) NextHop
*nexthop
= NULL
;
223 assert(manager
|| link
);
227 r
= nexthop_new(&nexthop
);
231 nexthop_copy(nexthop
, in
);
233 r
= set_ensure_put(nexthops
, &nexthop_hash_ops
, nexthop
);
239 nexthop
->link
= link
;
240 nexthop
->manager
= manager
;
249 static int nexthop_add_foreign(Manager
*manager
, Link
*link
, const NextHop
*in
, NextHop
**ret
) {
250 assert(manager
|| link
);
251 return nexthop_add_internal(manager
, link
, link
? &link
->nexthops_foreign
: &manager
->nexthops_foreign
, in
, ret
);
254 static int nexthop_add(Link
*link
, const NextHop
*in
, NextHop
**ret
) {
263 r
= nexthop_get(link
->manager
, NULL
, in
, &nexthop
);
265 r
= nexthop_get(NULL
, link
, in
, &nexthop
);
267 /* NextHop does not exist, create a new one */
268 r
= nexthop_add_internal(link
->manager
,
269 in
->blackhole
? NULL
: link
,
270 in
->blackhole
? &link
->manager
->nexthops
: &link
->nexthops
,
276 /* Take over a foreign nexthop */
277 r
= set_ensure_put(in
->blackhole
? &link
->manager
->nexthops
: &link
->nexthops
,
278 &nexthop_hash_ops
, nexthop
);
282 set_remove(in
->blackhole
? link
->manager
->nexthops_foreign
: link
->nexthops_foreign
, nexthop
);
284 /* NextHop exists, do nothing */
294 static int nexthop_update(Manager
*manager
, Link
*link
, NextHop
*nexthop
, const NextHop
*in
) {
298 /* link may be NULL. */
305 /* This updates nexthop ID if necessary, and register the nexthop to Manager. */
307 if (nexthop
->id
> 0) {
308 if (nexthop
->id
== in
->id
)
313 nexthops
= link
? link
->nexthops
: manager
->nexthops
;
315 nexthop
= set_remove(nexthops
, nexthop
);
319 nexthop
->id
= in
->id
;
321 r
= set_put(nexthops
, nexthop
);
325 /* On failure, revert the change. */
327 k
= set_put(nexthops
, nexthop
);
329 nexthop_free(nexthop
);
330 return k
< 0 ? k
: -EEXIST
;
333 return r
< 0 ? r
: -EEXIST
;
337 return hashmap_ensure_put(&manager
->nexthops_by_id
, NULL
, UINT32_TO_PTR(nexthop
->id
), nexthop
);
340 static void log_nexthop_debug(const NextHop
*nexthop
, uint32_t id
, const char *str
, const Link
*link
) {
341 _cleanup_free_
char *gw
= NULL
;
346 /* link may be NULL. */
351 (void) in_addr_to_string(nexthop
->family
, &nexthop
->gw
, &gw
);
353 if (nexthop
->id
== id
)
354 log_link_debug(link
, "%s nexthop: id: %"PRIu32
", gw: %s, blackhole: %s",
355 str
, nexthop
->id
, strna(gw
), yes_no(nexthop
->blackhole
));
357 log_link_debug(link
, "%s nexthop: id: %"PRIu32
"→%"PRIu32
", gw: %s, blackhole: %s",
358 str
, nexthop
->id
, id
, strna(gw
), yes_no(nexthop
->blackhole
));
361 static int link_nexthop_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
366 assert(link
->nexthop_remove_messages
> 0);
368 link
->nexthop_remove_messages
--;
370 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
373 r
= sd_netlink_message_get_errno(m
);
374 if (r
< 0 && r
!= -ENOENT
)
375 log_link_message_warning_errno(link
, m
, r
, "Could not drop nexthop, ignoring");
380 static int manager_nexthop_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Manager
*manager
) {
385 assert(manager
->nexthop_remove_messages
> 0);
387 manager
->nexthop_remove_messages
--;
389 r
= sd_netlink_message_get_errno(m
);
390 if (r
< 0 && r
!= -ENOENT
)
391 log_message_warning_errno(m
, r
, "Could not drop nexthop, ignoring");
396 static int nexthop_remove(const NextHop
*nexthop
, Manager
*manager
, Link
*link
) {
397 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
403 /* link may be NULL. */
405 if (nexthop
->id
== 0) {
406 log_link_debug(link
, "Cannot remove nexthop without valid ID, ignoring.");
410 log_nexthop_debug(nexthop
, nexthop
->id
, "Removing", link
);
412 r
= sd_rtnl_message_new_nexthop(manager
->rtnl
, &req
, RTM_DELNEXTHOP
, AF_UNSPEC
, RTPROT_UNSPEC
);
414 return log_link_error_errno(link
, r
, "Could not create RTM_DELNEXTHOP message: %m");
416 r
= sd_netlink_message_append_u32(req
, NHA_ID
, nexthop
->id
);
418 return log_link_error_errno(link
, r
, "Could not append NHA_ID attribute: %m");
421 r
= netlink_call_async(manager
->rtnl
, NULL
, req
, link_nexthop_remove_handler
,
422 link_netlink_destroy_callback
, link
);
424 r
= netlink_call_async(manager
->rtnl
, NULL
, req
, manager_nexthop_remove_handler
,
427 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
429 link_ref(link
); /* link may be NULL, link_ref() is OK with that */
432 link
->nexthop_remove_messages
++;
434 manager
->nexthop_remove_messages
++;
439 static int nexthop_configure(
440 const NextHop
*nexthop
,
442 link_netlink_message_handler_t callback
,
445 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
449 assert(link
->manager
);
450 assert(link
->manager
->rtnl
);
451 assert(link
->ifindex
> 0);
452 assert(IN_SET(nexthop
->family
, AF_INET
, AF_INET6
));
455 log_nexthop_debug(nexthop
, nexthop
->id
, "Configuring", link
);
457 r
= sd_rtnl_message_new_nexthop(link
->manager
->rtnl
, &req
,
458 RTM_NEWNEXTHOP
, nexthop
->family
,
461 return log_link_error_errno(link
, r
, "Could not create RTM_NEWNEXTHOP message: %m");
463 if (nexthop
->id
> 0) {
464 r
= sd_netlink_message_append_u32(req
, NHA_ID
, nexthop
->id
);
466 return log_link_error_errno(link
, r
, "Could not append NHA_ID attribute: %m");
469 if (nexthop
->blackhole
) {
470 r
= sd_netlink_message_append_flag(req
, NHA_BLACKHOLE
);
472 return log_link_error_errno(link
, r
, "Could not append NHA_BLACKHOLE attribute: %m");
474 r
= sd_netlink_message_append_u32(req
, NHA_OIF
, link
->ifindex
);
476 return log_link_error_errno(link
, r
, "Could not append NHA_OIF attribute: %m");
478 if (in_addr_is_set(nexthop
->family
, &nexthop
->gw
)) {
479 r
= netlink_message_append_in_addr_union(req
, NHA_GATEWAY
, nexthop
->family
, &nexthop
->gw
);
481 return log_link_error_errno(link
, r
, "Could not append NHA_GATEWAY attribute: %m");
483 if (nexthop
->onlink
> 0) {
484 r
= sd_rtnl_message_nexthop_set_flags(req
, RTNH_F_ONLINK
);
486 return log_link_error_errno(link
, r
, "Failed to set RTNH_F_ONLINK flag: %m");
491 k
= nexthop_add(link
, nexthop
, ret
);
493 return log_link_error_errno(link
, k
, "Could not add nexthop: %m");
495 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, callback
,
496 link_netlink_destroy_callback
, link
);
498 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
505 static int static_nexthop_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
509 assert(link
->static_nexthop_messages
> 0);
511 link
->static_nexthop_messages
--;
513 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
516 r
= sd_netlink_message_get_errno(m
);
517 if (r
< 0 && r
!= -EEXIST
) {
518 log_link_message_warning_errno(link
, m
, r
, "Could not set nexthop");
519 link_enter_failed(link
);
523 if (link
->static_nexthop_messages
== 0) {
524 log_link_debug(link
, "Nexthops set");
525 link
->static_nexthops_configured
= true;
526 link_check_ready(link
);
532 static int link_request_nexthop(
536 unsigned *message_counter
,
537 link_netlink_message_handler_t netlink_handler
,
543 log_nexthop_debug(nexthop
, nexthop
->id
, "Requesting", link
);
544 return link_queue_request(link
, REQUEST_TYPE_NEXTHOP
, nexthop
, consume_object
,
545 message_counter
, netlink_handler
, ret
);
548 int link_request_static_nexthops(Link
*link
, bool only_ipv4
) {
553 assert(link
->network
);
555 link
->static_nexthops_configured
= false;
557 HASHMAP_FOREACH(nh
, link
->network
->nexthops_by_section
) {
558 if (only_ipv4
&& nh
->family
!= AF_INET
)
561 r
= link_request_nexthop(link
, nh
, false, &link
->static_nexthop_messages
,
562 static_nexthop_handler
, NULL
);
564 return log_link_warning_errno(link
, r
, "Could not request nexthop: %m");
567 if (link
->static_nexthop_messages
== 0) {
568 link
->static_nexthops_configured
= true;
569 link_check_ready(link
);
571 log_link_debug(link
, "Requesting nexthops");
572 link_set_state(link
, LINK_STATE_CONFIGURING
);
578 static bool link_has_nexthop(const Link
*link
, const NextHop
*nexthop
) {
579 NextHop
*net_nexthop
;
587 HASHMAP_FOREACH(net_nexthop
, link
->network
->nexthops_by_section
)
588 if (nexthop_equal(net_nexthop
, nexthop
))
594 static bool links_have_nexthop(const Manager
*manager
, const NextHop
*nexthop
, const Link
*except
) {
599 HASHMAP_FOREACH(link
, manager
->links
) {
603 if (link_has_nexthop(link
, nexthop
))
610 static int manager_drop_nexthops_internal(Manager
*manager
, bool foreign
, const Link
*except
) {
617 nexthops
= foreign
? manager
->nexthops_foreign
: manager
->nexthops
;
618 SET_FOREACH(nexthop
, nexthops
) {
619 /* do not touch nexthop created by the kernel */
620 if (nexthop
->protocol
== RTPROT_KERNEL
)
623 /* The nexthop will be configured later, or already configured by a link. */
624 if (links_have_nexthop(manager
, nexthop
, except
))
627 /* The existing links do not have the nexthop. Let's drop this now. It may be
628 * re-configured later. */
629 k
= nexthop_remove(nexthop
, manager
, NULL
);
637 static int manager_drop_foreign_nexthops(Manager
*manager
) {
638 return manager_drop_nexthops_internal(manager
, true, NULL
);
641 static int manager_drop_nexthops(Manager
*manager
, const Link
*except
) {
642 return manager_drop_nexthops_internal(manager
, false, except
);
645 int link_drop_foreign_nexthops(Link
*link
) {
650 assert(link
->manager
);
652 SET_FOREACH(nexthop
, link
->nexthops_foreign
) {
653 /* do not touch nexthop created by the kernel */
654 if (nexthop
->protocol
== RTPROT_KERNEL
)
657 if (link_has_nexthop(link
, nexthop
))
658 k
= nexthop_add(link
, nexthop
, NULL
);
660 k
= nexthop_remove(nexthop
, link
->manager
, link
);
665 k
= manager_drop_foreign_nexthops(link
->manager
);
672 int link_drop_nexthops(Link
*link
) {
677 assert(link
->manager
);
679 SET_FOREACH(nexthop
, link
->nexthops
) {
680 /* do not touch nexthop created by the kernel */
681 if (nexthop
->protocol
== RTPROT_KERNEL
)
684 k
= nexthop_remove(nexthop
, link
->manager
, link
);
689 k
= manager_drop_nexthops(link
->manager
, link
);
696 static bool nexthop_is_ready_to_configure(Link
*link
, const NextHop
*nexthop
) {
700 if (nexthop
->blackhole
) {
701 if (link
->manager
->nexthop_remove_messages
> 0)
706 HASHMAP_FOREACH(l
, link
->manager
->links
) {
707 if (l
->address_remove_messages
> 0)
709 if (l
->nexthop_remove_messages
> 0)
711 if (l
->route_remove_messages
> 0)
716 if (nexthop
->id
== 0) {
719 ORDERED_SET_FOREACH(req
, link
->manager
->request_queue
) {
720 if (req
->type
!= REQUEST_TYPE_NEXTHOP
)
722 if (req
->nexthop
->id
!= 0)
723 return false; /* first configure nexthop with id. */
727 if (nexthop
->onlink
<= 0 &&
728 in_addr_is_set(nexthop
->family
, &nexthop
->gw
) &&
729 !manager_address_is_reachable(link
->manager
, nexthop
->family
, &nexthop
->gw
))
735 int request_process_nexthop(Request
*req
) {
741 assert(req
->nexthop
);
742 assert(req
->type
== REQUEST_TYPE_NEXTHOP
);
744 if (!link_is_ready_to_configure(req
->link
, false))
747 if (!nexthop_is_ready_to_configure(req
->link
, req
->nexthop
))
750 r
= nexthop_configure(req
->nexthop
, req
->link
, req
->netlink_handler
, &ret
);
754 if (req
->after_configure
) {
755 r
= req
->after_configure(req
, ret
);
763 int manager_rtnl_process_nexthop(sd_netlink
*rtnl
, sd_netlink_message
*message
, Manager
*m
) {
764 _cleanup_(nexthop_freep
) NextHop
*tmp
= NULL
;
765 NextHop
*nexthop
= NULL
;
775 if (sd_netlink_message_is_error(message
)) {
776 r
= sd_netlink_message_get_errno(message
);
778 log_message_warning_errno(message
, r
, "rtnl: failed to receive rule message, ignoring");
783 r
= sd_netlink_message_get_type(message
, &type
);
785 log_warning_errno(r
, "rtnl: could not get message type, ignoring: %m");
787 } else if (!IN_SET(type
, RTM_NEWNEXTHOP
, RTM_DELNEXTHOP
)) {
788 log_warning("rtnl: received unexpected message type %u when processing nexthop, ignoring.", type
);
792 r
= sd_netlink_message_read_u32(message
, NHA_OIF
, &ifindex
);
793 if (r
< 0 && r
!= -ENODATA
) {
794 log_warning_errno(r
, "rtnl: could not get NHA_OIF attribute, ignoring: %m");
798 log_warning("rtnl: received nexthop message with invalid ifindex %"PRIu32
", ignoring.", ifindex
);
802 r
= link_get(m
, ifindex
, &link
);
803 if (r
< 0 || !link
) {
805 log_warning("rtnl: received nexthop message for link (%"PRIu32
") we do not know about, ignoring", ifindex
);
810 r
= nexthop_new(&tmp
);
814 r
= sd_rtnl_message_get_family(message
, &tmp
->family
);
816 log_link_warning_errno(link
, r
, "rtnl: could not get nexthop family, ignoring: %m");
818 } else if (!IN_SET(tmp
->family
, AF_INET
, AF_INET6
)) {
819 log_link_debug(link
, "rtnl: received nexthop message with invalid family %d, ignoring.", tmp
->family
);
823 r
= sd_rtnl_message_nexthop_get_protocol(message
, &tmp
->protocol
);
825 log_link_warning_errno(link
, r
, "rtnl: could not get nexthop protocol, ignoring: %m");
829 r
= netlink_message_read_in_addr_union(message
, NHA_GATEWAY
, tmp
->family
, &tmp
->gw
);
830 if (r
< 0 && r
!= -ENODATA
) {
831 log_link_warning_errno(link
, r
, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m");
835 r
= sd_netlink_message_has_flag(message
, NHA_BLACKHOLE
);
837 log_link_warning_errno(link
, r
, "rtnl: could not get NHA_BLACKHOLE attribute, ignoring: %m");
842 r
= sd_netlink_message_read_u32(message
, NHA_ID
, &tmp
->id
);
844 log_link_warning_errno(link
, r
, "rtnl: received nexthop message without NHA_ID attribute, ignoring: %m");
847 log_link_warning_errno(link
, r
, "rtnl: could not get NHA_ID attribute, ignoring: %m");
849 } else if (tmp
->id
== 0) {
850 log_link_warning(link
, "rtnl: received nexthop message with invalid nexthop ID, ignoring: %m");
854 /* All blackhole nexthops are managed by Manager. Note that the linux kernel does not set
855 * NHA_OID attribute when NHA_BLACKHOLE is set. Just for safety. */
859 r
= nexthop_get(m
, link
, tmp
, &nexthop
);
863 /* The nexthop may be created without setting NHA_ID. */
868 (void) nexthop_get(m
, link
, tmp
, &nexthop
);
876 log_nexthop_debug(nexthop
, tmp
->id
, "Received remembered", link
);
878 log_nexthop_debug(tmp
, tmp
->id
, "Remembering foreign", link
);
879 r
= nexthop_add_foreign(m
, link
, tmp
, &nexthop
);
881 log_link_warning_errno(link
, r
, "Could not remember foreign nexthop, ignoring: %m");
886 r
= nexthop_update(m
, link
, nexthop
, tmp
);
888 log_link_warning_errno(link
, r
, "Could not update nexthop, ignoring: %m");
893 log_nexthop_debug(tmp
, tmp
->id
, nexthop
? "Forgetting" : "Kernel removed unknown", link
);
894 nexthop_free(nexthop
);
898 assert_not_reached("Received invalid RTNL message type");
904 static int nexthop_section_verify(NextHop
*nh
) {
905 if (section_is_invalid(nh
->section
))
908 if (nh
->family
== AF_UNSPEC
)
909 /* When no Gateway= is specified, assume IPv4. */
910 nh
->family
= AF_INET
;
912 if (nh
->blackhole
&& in_addr_is_set(nh
->family
, &nh
->gw
))
913 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
914 "%s: blackhole nexthop cannot have gateway address. "
915 "Ignoring [NextHop] section from line %u.",
916 nh
->section
->filename
, nh
->section
->line
);
918 if (nh
->onlink
< 0 && in_addr_is_set(nh
->family
, &nh
->gw
) &&
919 ordered_hashmap_isempty(nh
->network
->addresses_by_section
)) {
920 /* If no address is configured, in most cases the gateway cannot be reachable.
921 * TODO: we may need to improve the condition above. */
922 log_warning("%s: Gateway= without static address configured. "
923 "Enabling OnLink= option.",
924 nh
->section
->filename
);
931 void network_drop_invalid_nexthops(Network
*network
) {
936 HASHMAP_FOREACH(nh
, network
->nexthops_by_section
)
937 if (nexthop_section_verify(nh
) < 0)
941 int config_parse_nexthop_id(
943 const char *filename
,
946 unsigned section_line
,
953 _cleanup_(nexthop_free_or_set_invalidp
) NextHop
*n
= NULL
;
954 Network
*network
= userdata
;
964 r
= nexthop_new_static(network
, filename
, section_line
, &n
);
968 if (isempty(rvalue
)) {
974 r
= safe_atou32(rvalue
, &id
);
976 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
977 "Could not parse nexthop id \"%s\", ignoring assignment: %m", rvalue
);
981 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
982 "Invalid nexthop id \"%s\", ignoring assignment: %m", rvalue
);
991 int config_parse_nexthop_gateway(
993 const char *filename
,
996 unsigned section_line
,
1003 _cleanup_(nexthop_free_or_set_invalidp
) NextHop
*n
= NULL
;
1004 Network
*network
= userdata
;
1013 r
= nexthop_new_static(network
, filename
, section_line
, &n
);
1017 if (isempty(rvalue
)) {
1018 n
->family
= AF_UNSPEC
;
1019 n
->gw
= IN_ADDR_NULL
;
1025 r
= in_addr_from_string_auto(rvalue
, &n
->family
, &n
->gw
);
1027 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1028 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
1036 int config_parse_nexthop_family(
1038 const char *filename
,
1040 const char *section
,
1041 unsigned section_line
,
1048 _cleanup_(nexthop_free_or_set_invalidp
) NextHop
*n
= NULL
;
1049 Network
*network
= userdata
;
1059 r
= nexthop_new_static(network
, filename
, section_line
, &n
);
1063 if (isempty(rvalue
) &&
1064 !in_addr_is_set(n
->family
, &n
->gw
)) {
1065 /* Accept an empty string only when Gateway= is null or not specified. */
1066 n
->family
= AF_UNSPEC
;
1071 a
= nexthop_address_family_from_string(rvalue
);
1073 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1074 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
1078 if (in_addr_is_set(n
->family
, &n
->gw
) &&
1079 ((a
== ADDRESS_FAMILY_IPV4
&& n
->family
== AF_INET6
) ||
1080 (a
== ADDRESS_FAMILY_IPV6
&& n
->family
== AF_INET
))) {
1081 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1082 "Specified family '%s' conflicts with the family of the previously specified Gateway=, "
1083 "ignoring assignment.", rvalue
);
1088 case ADDRESS_FAMILY_IPV4
:
1089 n
->family
= AF_INET
;
1091 case ADDRESS_FAMILY_IPV6
:
1092 n
->family
= AF_INET6
;
1095 assert_not_reached("Invalid family.");
1102 int config_parse_nexthop_onlink(
1104 const char *filename
,
1106 const char *section
,
1107 unsigned section_line
,
1114 _cleanup_(nexthop_free_or_set_invalidp
) NextHop
*n
= NULL
;
1115 Network
*network
= userdata
;
1124 r
= nexthop_new_static(network
, filename
, section_line
, &n
);
1128 if (isempty(rvalue
)) {
1134 r
= parse_boolean(rvalue
);
1136 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1137 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
1147 int config_parse_nexthop_blackhole(
1149 const char *filename
,
1151 const char *section
,
1152 unsigned section_line
,
1159 _cleanup_(nexthop_free_or_set_invalidp
) NextHop
*n
= NULL
;
1160 Network
*network
= userdata
;
1169 r
= nexthop_new_static(network
, filename
, section_line
, &n
);
1173 r
= parse_boolean(rvalue
);
1175 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1176 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);