1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "hostname-util.h"
8 #include "memstream-util.h"
9 #include "netif-naming-scheme.h"
10 #include "network-generator.h"
11 #include "parse-util.h"
12 #include "proc-cmdline.h"
13 #include "socket-util.h"
14 #include "string-table.h"
15 #include "string-util.h"
20 ip={dhcp|on|any|dhcp6|auto6|either6|link6|link-local}
21 ip=<interface>:{dhcp|on|any|dhcp6|auto6|link6|link-local}[:[<mtu>][:<macaddr>]]
22 ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|link6|ibft|link-local}[:[<mtu>][:<macaddr>]]
23 ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|link6|ibft|link-local}[:[<dns1>][:<dns2>]]
24 rd.route=<net>/<netmask>:<gateway>[:<interface>]
25 nameserver=<IP> [nameserver=<IP> ...]
29 ifname=<interface>:<MAC>
30 net.ifname_policy=policy1[,policy2,...][,<MAC>] # This is an original rule, not supported by other tools.
33 vlan=<vlanname>:<phydevice>
34 bond=<bondname>[:<bondslaves>:[:<options>[:<mtu>]]]
35 team=<teammaster>:<teamslaves> # not supported
36 bridge=<bridgename>:<ethnames>
46 static const char * const dracut_dhcp_type_table
[_DHCP_TYPE_MAX
] = {
47 [DHCP_TYPE_NONE
] = "none",
48 [DHCP_TYPE_OFF
] = "off",
49 [DHCP_TYPE_ON
] = "on",
50 [DHCP_TYPE_ANY
] = "any",
51 [DHCP_TYPE_DHCP
] = "dhcp",
52 [DHCP_TYPE_DHCP6
] = "dhcp6",
53 [DHCP_TYPE_AUTO6
] = "auto6",
54 [DHCP_TYPE_EITHER6
] = "either6",
55 [DHCP_TYPE_IBFT
] = "ibft",
56 [DHCP_TYPE_LINK6
] = "link6",
57 [DHCP_TYPE_LINK_LOCAL
] = "link-local",
60 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dracut_dhcp_type
, DHCPType
);
62 static const char * const networkd_dhcp_type_table
[_DHCP_TYPE_MAX
] = {
63 [DHCP_TYPE_NONE
] = "no",
64 [DHCP_TYPE_OFF
] = "no",
65 [DHCP_TYPE_ON
] = "yes",
66 [DHCP_TYPE_ANY
] = "yes",
67 [DHCP_TYPE_DHCP
] = "ipv4",
68 [DHCP_TYPE_DHCP6
] = "ipv6",
69 [DHCP_TYPE_AUTO6
] = "no", /* TODO: enable other setting? */
70 [DHCP_TYPE_EITHER6
] = "ipv6", /* TODO: enable other setting? */
71 [DHCP_TYPE_IBFT
] = "no",
72 [DHCP_TYPE_LINK6
] = "no",
73 [DHCP_TYPE_LINK_LOCAL
] = "no",
76 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(networkd_dhcp_type
, DHCPType
);
78 static const char * const networkd_ipv6ra_type_table
[_DHCP_TYPE_MAX
] = {
79 [DHCP_TYPE_NONE
] = "no",
80 [DHCP_TYPE_OFF
] = "no",
81 [DHCP_TYPE_LINK6
] = "no",
82 [DHCP_TYPE_LINK_LOCAL
] = "no",
83 /* We omit the other entries, to leave the default in effect */
86 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(networkd_ipv6ra_type
, DHCPType
);
88 static const char * const networkd_link_local_type_table
[_DHCP_TYPE_MAX
] = {
89 [DHCP_TYPE_NONE
] = "no",
90 [DHCP_TYPE_OFF
] = "no",
91 [DHCP_TYPE_LINK6
] = "ipv6",
92 [DHCP_TYPE_LINK_LOCAL
] = "yes",
93 /* We omit the other entries, to leave the default in effect */
96 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(networkd_link_local_type
, DHCPType
);
98 static Address
*address_free(Address
*address
) {
102 if (address
->network
)
103 LIST_REMOVE(addresses
, address
->network
->addresses
, address
);
105 return mfree(address
);
108 static int address_new(Network
*network
, int family
, unsigned char prefixlen
,
109 union in_addr_union
*addr
, union in_addr_union
*peer
, Address
**ret
) {
113 assert(IN_SET(family
, AF_INET
, AF_INET6
));
116 address
= new(Address
, 1);
120 *address
= (Address
) {
122 .prefixlen
= prefixlen
,
124 .peer
= peer
? *peer
: IN_ADDR_NULL
,
127 LIST_PREPEND(addresses
, network
->addresses
, address
);
129 address
->network
= network
;
136 static Route
*route_free(Route
*route
) {
141 LIST_REMOVE(routes
, route
->network
->routes
, route
);
146 static int route_new(Network
*network
, int family
, unsigned char prefixlen
,
147 union in_addr_union
*dest
, union in_addr_union
*gateway
, Route
**ret
) {
151 assert(IN_SET(family
, AF_INET
, AF_INET6
));
152 assert(dest
|| gateway
);
154 route
= new(Route
, 1);
160 .prefixlen
= prefixlen
,
161 .dest
= dest
? *dest
: IN_ADDR_NULL
,
162 .gateway
= gateway
? *gateway
: IN_ADDR_NULL
,
165 LIST_PREPEND(routes
, network
->routes
, route
);
167 route
->network
= network
;
174 static Network
*network_free(Network
*network
) {
181 free(network
->ifname
);
182 free(network
->hostname
);
183 strv_free(network
->dns
);
185 free(network
->bridge
);
188 while ((address
= network
->addresses
))
189 address_free(address
);
191 while ((route
= network
->routes
))
194 return mfree(network
);
197 DEFINE_TRIVIAL_CLEANUP_FUNC(Network
*, network_free
);
199 static int network_new(Context
*context
, const char *name
, Network
**ret
) {
200 _cleanup_(network_freep
) Network
*network
= NULL
;
201 _cleanup_free_
char *ifname
= NULL
;
206 if (!isempty(name
) && !ifname_valid(name
))
209 ifname
= strdup(name
);
213 network
= new(Network
, 1);
217 *network
= (Network
) {
218 .ifname
= TAKE_PTR(ifname
),
219 .dhcp_type
= _DHCP_TYPE_INVALID
,
223 r
= hashmap_ensure_put(&context
->networks_by_name
, &string_hash_ops
, network
->ifname
, network
);
234 Network
*network_get(Context
*context
, const char *ifname
) {
235 return hashmap_get(context
->networks_by_name
, ifname
);
238 static NetDev
*netdev_free(NetDev
*netdev
) {
242 free(netdev
->ifname
);
244 return mfree(netdev
);
247 DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev
*, netdev_free
);
249 static int netdev_new(Context
*context
, const char *_kind
, const char *_ifname
, NetDev
**ret
) {
250 _cleanup_(netdev_freep
) NetDev
*netdev
= NULL
;
251 _cleanup_free_
char *kind
= NULL
, *ifname
= NULL
;
257 if (!ifname_valid(_ifname
))
260 kind
= strdup(_kind
);
264 ifname
= strdup(_ifname
);
268 netdev
= new(NetDev
, 1);
273 .kind
= TAKE_PTR(kind
),
274 .ifname
= TAKE_PTR(ifname
),
277 r
= hashmap_ensure_put(&context
->netdevs_by_name
, &string_hash_ops
, netdev
->ifname
, netdev
);
288 NetDev
*netdev_get(Context
*context
, const char *ifname
) {
289 return hashmap_get(context
->netdevs_by_name
, ifname
);
292 static Link
*link_free(Link
*link
) {
296 free(link
->filename
);
298 strv_free(link
->policies
);
299 strv_free(link
->alt_policies
);
303 DEFINE_TRIVIAL_CLEANUP_FUNC(Link
*, link_free
);
308 const struct hw_addr_data
*mac
,
311 _cleanup_(link_freep
) Link
*link
= NULL
;
312 _cleanup_free_
char *ifname
= NULL
, *filename
= NULL
;
319 if (!ifname_valid(name
))
322 ifname
= strdup(name
);
326 filename
= strdup(name
);
332 filename
= strdup(hw_addr_is_null(mac
) ? "default" :
333 HW_ADDR_TO_STR_FULL(mac
, HW_ADDR_TO_STRING_NO_COLON
));
343 .filename
= TAKE_PTR(filename
),
344 .ifname
= TAKE_PTR(ifname
),
348 r
= hashmap_ensure_put(&context
->links_by_filename
, &string_hash_ops
, link
->filename
, link
);
359 Link
*link_get(Context
*context
, const char *filename
) {
362 return hashmap_get(context
->links_by_filename
, filename
);
365 static int network_set_dhcp_type(Context
*context
, const char *ifname
, const char *dhcp_type
) {
374 t
= dracut_dhcp_type_from_string(dhcp_type
);
378 network
= network_get(context
, ifname
);
380 r
= network_new(context
, ifname
, &network
);
385 network
->dhcp_type
= t
;
389 static int network_set_hostname(Context
*context
, const char *ifname
, const char *hostname
) {
395 network
= network_get(context
, ifname
);
399 return free_and_strdup(&network
->hostname
, hostname
);
402 static int network_set_mtu(Context
*context
, const char *ifname
, const char *mtu
) {
411 network
= network_get(context
, ifname
);
415 return parse_mtu(AF_UNSPEC
, mtu
, &network
->mtu
);
418 static int network_set_mac_address(Context
*context
, const char *ifname
, const char *mac
) {
425 network
= network_get(context
, ifname
);
429 return parse_ether_addr(mac
, &network
->mac
);
432 static int network_set_address(Context
*context
, const char *ifname
, int family
, unsigned char prefixlen
,
433 union in_addr_union
*addr
, union in_addr_union
*peer
) {
438 assert(IN_SET(family
, AF_INET
, AF_INET6
));
441 if (!in_addr_is_set(family
, addr
))
444 network
= network_get(context
, ifname
);
448 return address_new(network
, family
, prefixlen
, addr
, peer
, NULL
);
451 static int network_set_route(Context
*context
, const char *ifname
, int family
, unsigned char prefixlen
,
452 union in_addr_union
*dest
, union in_addr_union
*gateway
) {
458 assert(IN_SET(family
, AF_INET
, AF_INET6
));
460 if (!(dest
&& in_addr_is_set(family
, dest
)) &&
461 !(gateway
&& in_addr_is_set(family
, gateway
)))
464 network
= network_get(context
, ifname
);
466 r
= network_new(context
, ifname
, &network
);
471 return route_new(network
, family
, prefixlen
, dest
, gateway
, NULL
);
474 static int network_set_dns(Context
*context
, const char *ifname
, int family
, const char *dns
) {
475 union in_addr_union a
;
481 assert(IN_SET(family
, AF_UNSPEC
, AF_INET
, AF_INET6
));
484 if (family
== AF_UNSPEC
)
485 r
= in_addr_from_string_auto(dns
, &family
, &a
);
487 r
= in_addr_from_string(family
, dns
, &a
);
491 network
= network_get(context
, ifname
);
493 r
= network_new(context
, ifname
, &network
);
498 return strv_extend(&network
->dns
, dns
);
501 static int network_set_dhcp_use_dns(Context
*context
, const char *ifname
, bool value
) {
508 network
= network_get(context
, ifname
);
510 r
= network_new(context
, ifname
, &network
);
515 network
->dhcp_use_dns
= value
;
520 static int network_set_vlan(Context
*context
, const char *ifname
, const char *value
) {
527 network
= network_get(context
, ifname
);
529 r
= network_new(context
, ifname
, &network
);
534 return free_and_strdup(&network
->vlan
, value
);
537 static int network_set_bridge(Context
*context
, const char *ifname
, const char *value
) {
544 network
= network_get(context
, ifname
);
546 r
= network_new(context
, ifname
, &network
);
551 return free_and_strdup(&network
->bridge
, value
);
554 static int network_set_bond(Context
*context
, const char *ifname
, const char *value
) {
561 network
= network_get(context
, ifname
);
563 r
= network_new(context
, ifname
, &network
);
568 return free_and_strdup(&network
->bond
, value
);
571 static int parse_cmdline_ip_mtu_mac(Context
*context
, const char *ifname
, const char *value
) {
579 /* [<mtu>][:<macaddr>] */
581 p
= strchr(value
, ':');
585 mtu
= strndupa_safe(value
, p
- value
);
587 r
= network_set_mtu(context
, ifname
, mtu
);
591 if (!p
|| isempty(p
+ 1))
594 r
= network_set_mac_address(context
, ifname
, p
+ 1);
601 static int parse_ip_address_one(int family
, const char **value
, union in_addr_union
*ret
) {
602 const char *p
, *q
, *buf
;
605 assert(IN_SET(family
, AF_INET
, AF_INET6
));
609 p
= ASSERT_PTR(*value
);
616 if (family
== AF_INET6
) {
620 q
= strchr(p
+ 1, ']');
627 buf
= strndupa_safe(p
+ 1, q
- p
- 1);
634 buf
= strndupa_safe(p
, q
- p
);
638 r
= in_addr_from_string(family
, buf
, ret
);
646 static int parse_netmask_or_prefixlen(int family
, const char **value
, unsigned char *ret
) {
647 union in_addr_union netmask
;
651 assert(IN_SET(family
, AF_INET
, AF_INET6
));
656 r
= parse_ip_address_one(family
, value
, &netmask
);
658 if (family
== AF_INET6
)
659 /* TODO: Not supported yet. */
662 *ret
= in4_addr_netmask_to_prefixlen(&netmask
.in
);
664 *ret
= family
== AF_INET6
? 128 : 32;
666 p
= strchr(*value
, ':');
670 q
= strndupa_safe(*value
, p
- *value
);
671 r
= safe_atou8(q
, ret
);
681 static int parse_ip_dns_address_one(Context
*context
, const char *ifname
, const char **value
) {
682 const char *p
, *q
, *buf
;
689 p
= ASSERT_PTR(*value
);
695 q
= strchr(p
+ 1, ']');
698 if (!IN_SET(q
[1], ':', '\0'))
701 buf
= strndupa_safe(p
+ 1, q
- p
- 1);
709 buf
= strndupa_safe(*value
, q
- *value
);
715 r
= network_set_dns(context
, ifname
, family
, buf
);
723 static int parse_cmdline_ip_address(Context
*context
, int family
, const char *value
) {
724 union in_addr_union addr
= {}, peer
= {}, gateway
= {};
725 const char *hostname
= NULL
, *ifname
, *dhcp_type
, *p
;
726 unsigned char prefixlen
;
730 assert(IN_SET(family
, AF_INET
, AF_INET6
));
733 /* ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[<mtu>][:<macaddr>]]
734 * ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[<dns1>][:<dns2>]] */
736 r
= parse_ip_address_one(family
, &value
, &addr
);
739 r
= parse_ip_address_one(family
, &value
, &peer
);
742 r
= parse_ip_address_one(family
, &value
, &gateway
);
745 r
= parse_netmask_or_prefixlen(family
, &value
, &prefixlen
);
750 p
= strchr(value
, ':');
755 hostname
= strndupa_safe(value
, p
- value
);
756 if (!hostname_is_valid(hostname
, 0))
763 p
= strchr(value
, ':');
767 ifname
= strndupa_safe(value
, p
- value
);
772 p
= strchr(value
, ':');
776 dhcp_type
= strndupa_safe(value
, p
- value
);
778 r
= network_set_dhcp_type(context
, ifname
, dhcp_type
);
783 r
= network_set_hostname(context
, ifname
, hostname
);
787 r
= network_set_address(context
, ifname
, family
, prefixlen
, &addr
, &peer
);
791 r
= network_set_route(context
, ifname
, family
, 0, NULL
, &gateway
);
798 /* First, try [<mtu>][:<macaddr>] */
799 r
= parse_cmdline_ip_mtu_mac(context
, ifname
, p
+ 1);
803 /* Next, try [<dns1>][:<dns2>] */
805 r
= parse_ip_dns_address_one(context
, ifname
, &value
);
809 value
+= *value
== ':';
810 r
= parse_ip_dns_address_one(context
, ifname
, &value
);
814 /* refuse unexpected trailing strings */
821 static int parse_cmdline_ip_interface(Context
*context
, const char *value
) {
822 const char *ifname
, *dhcp_type
, *p
;
828 /* ip=<interface>:{dhcp|on|any|dhcp6|auto6|link6}[:[<mtu>][:<macaddr>]] */
830 p
= strchr(value
, ':');
834 ifname
= strndupa_safe(value
, p
- value
);
837 p
= strchr(value
, ':');
841 dhcp_type
= strndupa_safe(value
, p
- value
);
843 r
= network_set_dhcp_type(context
, ifname
, dhcp_type
);
850 return parse_cmdline_ip_mtu_mac(context
, ifname
, p
+ 1);
853 static int parse_cmdline_ip(Context
*context
, const char *key
, const char *value
) {
860 if (proc_cmdline_value_missing(key
, value
))
863 p
= strchr(value
, ':');
865 /* ip={dhcp|on|any|dhcp6|auto6|either6|link6} */
866 return network_set_dhcp_type(context
, "", value
);
869 return parse_cmdline_ip_address(context
, AF_INET6
, value
);
871 r
= parse_cmdline_ip_address(context
, AF_INET
, value
);
873 return parse_cmdline_ip_interface(context
, value
);
878 static int parse_cmdline_rd_route(Context
*context
, const char *key
, const char *value
) {
879 union in_addr_union addr
= {}, gateway
= {};
880 unsigned char prefixlen
;
887 /* rd.route=<net>/<netmask>:<gateway>[:<interface>] */
889 if (proc_cmdline_value_missing(key
, value
))
892 if (value
[0] == '[') {
893 p
= strchr(value
, ']');
900 buf
= strndupa_safe(value
+ 1, p
- value
- 1);
904 p
= strchr(value
, ':');
908 buf
= strndupa_safe(value
, p
- value
);
913 r
= in_addr_prefix_from_string(buf
, family
, &addr
, &prefixlen
);
917 p
= strchr(value
, ':');
919 value
= strjoina(value
, ":");
921 r
= parse_ip_address_one(family
, &value
, &gateway
);
925 return network_set_route(context
, value
, family
, prefixlen
, &addr
, &gateway
);
928 static int parse_cmdline_nameserver(Context
*context
, const char *key
, const char *value
) {
932 if (proc_cmdline_value_missing(key
, value
))
935 return network_set_dns(context
, "", AF_UNSPEC
, value
);
938 static int parse_cmdline_rd_peerdns(Context
*context
, const char *key
, const char *value
) {
944 if (proc_cmdline_value_missing(key
, value
))
945 return network_set_dhcp_use_dns(context
, "", true);
947 r
= parse_boolean(value
);
951 return network_set_dhcp_use_dns(context
, "", r
);
954 static int parse_cmdline_vlan(Context
*context
, const char *key
, const char *value
) {
955 const char *name
, *p
;
962 if (proc_cmdline_value_missing(key
, value
))
965 p
= strchr(value
, ':');
969 name
= strndupa_safe(value
, p
- value
);
971 netdev
= netdev_get(context
, name
);
973 r
= netdev_new(context
, "vlan", name
, &netdev
);
978 return network_set_vlan(context
, p
+ 1, name
);
981 static int parse_cmdline_bridge(Context
*context
, const char *key
, const char *value
) {
982 const char *name
, *p
;
989 if (proc_cmdline_value_missing(key
, value
))
992 p
= strchr(value
, ':');
996 name
= strndupa_safe(value
, p
- value
);
998 netdev
= netdev_get(context
, name
);
1000 r
= netdev_new(context
, "bridge", name
, &netdev
);
1010 _cleanup_free_
char *word
= NULL
;
1012 r
= extract_first_word(&p
, &word
, ",", 0);
1016 r
= network_set_bridge(context
, word
, name
);
1022 static int parse_cmdline_bond(Context
*context
, const char *key
, const char *value
) {
1023 const char *name
, *slaves
, *p
;
1030 if (proc_cmdline_value_missing(key
, value
))
1033 p
= strchr(value
, ':');
1037 name
= strndupa_safe(value
, p
- value
);
1039 netdev
= netdev_get(context
, name
);
1041 r
= netdev_new(context
, "bond", name
, &netdev
);
1047 p
= strchr(value
, ':');
1051 slaves
= strndupa_safe(value
, p
- value
);
1053 if (isempty(slaves
))
1056 for (const char *q
= slaves
; ; ) {
1057 _cleanup_free_
char *word
= NULL
;
1059 r
= extract_first_word(&q
, &word
, ",", 0);
1065 r
= network_set_bond(context
, word
, name
);
1074 p
= strchr(value
, ':');
1076 /* TODO: set bonding options */
1079 return parse_mtu(AF_UNSPEC
, p
+ 1, &netdev
->mtu
);
1082 static int parse_cmdline_ifname(Context
*context
, const char *key
, const char *value
) {
1083 struct hw_addr_data mac
;
1084 const char *name
, *p
;
1090 /* ifname=<interface>:<MAC> */
1092 if (proc_cmdline_value_missing(key
, value
))
1095 p
= strchr(value
, ':');
1099 name
= strndupa_safe(value
, p
- value
);
1101 r
= parse_hw_addr(p
+ 1, &mac
);
1105 return link_new(context
, name
, &mac
, NULL
);
1108 static int parse_cmdline_ifname_policy(Context
*context
, const char *key
, const char *value
) {
1109 _cleanup_strv_free_
char **policies
= NULL
, **alt_policies
= NULL
;
1110 struct hw_addr_data mac
= HW_ADDR_NULL
;
1117 /* net.ifname_policy=policy1[,policy2,...][,<MAC>] */
1119 if (proc_cmdline_value_missing(key
, value
))
1122 for (const char *q
= value
; ; ) {
1123 _cleanup_free_
char *word
= NULL
;
1126 r
= extract_first_word(&q
, &word
, ",", 0);
1132 p
= name_policy_from_string(word
);
1134 r
= parse_hw_addr(word
, &mac
);
1138 if (hw_addr_is_null(&mac
))
1147 if (alternative_names_policy_from_string(word
) >= 0) {
1148 r
= strv_extend(&alt_policies
, word
);
1153 r
= strv_consume(&policies
, TAKE_PTR(word
));
1158 if (strv_isempty(policies
))
1161 r
= link_new(context
, NULL
, &mac
, &link
);
1165 link
->policies
= TAKE_PTR(policies
);
1166 link
->alt_policies
= TAKE_PTR(alt_policies
);
1170 int parse_cmdline_item(const char *key
, const char *value
, void *data
) {
1171 Context
*context
= ASSERT_PTR(data
);
1175 if (proc_cmdline_key_streq(key
, "ip"))
1176 return parse_cmdline_ip(context
, key
, value
);
1177 if (proc_cmdline_key_streq(key
, "rd.route"))
1178 return parse_cmdline_rd_route(context
, key
, value
);
1179 if (proc_cmdline_key_streq(key
, "nameserver"))
1180 return parse_cmdline_nameserver(context
, key
, value
);
1181 if (proc_cmdline_key_streq(key
, "rd.peerdns"))
1182 return parse_cmdline_rd_peerdns(context
, key
, value
);
1183 if (proc_cmdline_key_streq(key
, "vlan"))
1184 return parse_cmdline_vlan(context
, key
, value
);
1185 if (proc_cmdline_key_streq(key
, "bridge"))
1186 return parse_cmdline_bridge(context
, key
, value
);
1187 if (proc_cmdline_key_streq(key
, "bond"))
1188 return parse_cmdline_bond(context
, key
, value
);
1189 if (proc_cmdline_key_streq(key
, "ifname"))
1190 return parse_cmdline_ifname(context
, key
, value
);
1191 if (proc_cmdline_key_streq(key
, "net.ifname_policy"))
1192 return parse_cmdline_ifname_policy(context
, key
, value
);
1197 int context_merge_networks(Context
*context
) {
1198 Network
*all
, *network
;
1203 /* Copy settings about the following options
1204 rd.route=<net>/<netmask>:<gateway>[:<interface>]
1205 nameserver=<IP> [nameserver=<IP> ...]
1208 all
= network_get(context
, "");
1212 if (hashmap_size(context
->networks_by_name
) <= 1)
1215 HASHMAP_FOREACH(network
, context
->networks_by_name
) {
1219 network
->dhcp_use_dns
= all
->dhcp_use_dns
;
1221 r
= strv_extend_strv(&network
->dns
, all
->dns
, false);
1225 LIST_FOREACH(routes
, route
, all
->routes
) {
1226 r
= route_new(network
, route
->family
, route
->prefixlen
, &route
->dest
, &route
->gateway
, NULL
);
1232 assert_se(hashmap_remove(context
->networks_by_name
, "") == all
);
1237 void context_clear(Context
*context
) {
1241 hashmap_free_with_destructor(context
->networks_by_name
, network_free
);
1242 hashmap_free_with_destructor(context
->netdevs_by_name
, netdev_free
);
1243 hashmap_free_with_destructor(context
->links_by_filename
, link_free
);
1246 static int address_dump(Address
*address
, FILE *f
) {
1253 IN_ADDR_PREFIX_TO_STRING(address
->family
, &address
->address
, address
->prefixlen
));
1254 if (in_addr_is_set(address
->family
, &address
->peer
))
1255 fprintf(f
, "Peer=%s\n",
1256 IN_ADDR_TO_STRING(address
->family
, &address
->peer
));
1260 static int route_dump(Route
*route
, FILE *f
) {
1264 fputs("\n[Route]\n", f
);
1265 if (in_addr_is_set(route
->family
, &route
->dest
))
1266 fprintf(f
, "Destination=%s\n",
1267 IN_ADDR_PREFIX_TO_STRING(route
->family
, &route
->dest
, route
->prefixlen
));
1268 if (in_addr_is_set(route
->family
, &route
->gateway
))
1269 fprintf(f
, "Gateway=%s\n",
1270 IN_ADDR_TO_STRING(route
->family
, &route
->gateway
));
1275 void network_dump(Network
*network
, FILE *f
) {
1281 fputs("[Match]\n", f
);
1283 if (isempty(network
->ifname
))
1284 /* If the interface name is not specified, then let's make the .network file match the all
1285 * physical interfaces. */
1287 "Type=!loopback\n", f
);
1289 fprintf(f
, "Name=%s\n", network
->ifname
);
1291 fputs("\n[Link]\n", f
);
1293 if (!ether_addr_is_null(&network
->mac
))
1294 fprintf(f
, "MACAddress=%s\n", ETHER_ADDR_TO_STR(&network
->mac
));
1295 if (network
->mtu
> 0)
1296 fprintf(f
, "MTUBytes=%" PRIu32
"\n", network
->mtu
);
1298 fputs("\n[Network]\n", f
);
1300 dhcp
= networkd_dhcp_type_to_string(network
->dhcp_type
);
1302 fprintf(f
, "DHCP=%s\n", dhcp
);
1305 ll
= networkd_link_local_type_to_string(network
->dhcp_type
);
1307 fprintf(f
, "LinkLocalAddressing=%s\n", ll
);
1310 ra
= networkd_ipv6ra_type_to_string(network
->dhcp_type
);
1312 fprintf(f
, "IPv6AcceptRA=%s\n", ra
);
1314 if (!strv_isempty(network
->dns
))
1315 STRV_FOREACH(dns
, network
->dns
)
1316 fprintf(f
, "DNS=%s\n", *dns
);
1319 fprintf(f
, "VLAN=%s\n", network
->vlan
);
1321 if (network
->bridge
)
1322 fprintf(f
, "Bridge=%s\n", network
->bridge
);
1325 fprintf(f
, "Bond=%s\n", network
->bond
);
1327 fputs("\n[DHCP]\n", f
);
1329 if (!isempty(network
->hostname
))
1330 fprintf(f
, "Hostname=%s\n", network
->hostname
);
1332 if (network
->dhcp_use_dns
>= 0)
1333 fprintf(f
, "UseDNS=%s\n", yes_no(network
->dhcp_use_dns
));
1335 LIST_FOREACH(addresses
, address
, network
->addresses
)
1336 (void) address_dump(address
, f
);
1338 LIST_FOREACH(routes
, route
, network
->routes
)
1339 (void) route_dump(route
, f
);
1342 void netdev_dump(NetDev
*netdev
, FILE *f
) {
1353 if (netdev
->mtu
> 0)
1354 fprintf(f
, "MTUBytes=%" PRIu32
"\n", netdev
->mtu
);
1357 void link_dump(Link
*link
, FILE *f
) {
1361 fputs("[Match]\n", f
);
1363 if (!hw_addr_is_null(&link
->mac
))
1364 fprintf(f
, "MACAddress=%s\n", HW_ADDR_TO_STR(&link
->mac
));
1366 fputs("OriginalName=*\n", f
);
1368 fputs("\n[Link]\n", f
);
1370 if (!isempty(link
->ifname
))
1371 fprintf(f
, "Name=%s\n", link
->ifname
);
1373 if (!strv_isempty(link
->policies
)) {
1374 fputs("NamePolicy=", f
);
1375 fputstrv(f
, link
->policies
, " ", NULL
);
1379 if (!strv_isempty(link
->alt_policies
)) {
1380 fputs("AlternativeNamesPolicy=", f
);
1381 fputstrv(f
, link
->alt_policies
, " ", NULL
);
1386 int network_format(Network
*network
, char **ret
) {
1387 _cleanup_(memstream_done
) MemStream m
= {};
1393 f
= memstream_init(&m
);
1397 network_dump(network
, f
);
1399 return memstream_finalize(&m
, ret
, NULL
);
1402 int netdev_format(NetDev
*netdev
, char **ret
) {
1403 _cleanup_(memstream_done
) MemStream m
= {};
1409 f
= memstream_init(&m
);
1413 netdev_dump(netdev
, f
);
1415 return memstream_finalize(&m
, ret
, NULL
);
1418 int link_format(Link
*link
, char **ret
) {
1419 _cleanup_(memstream_done
) MemStream m
= {};
1425 f
= memstream_init(&m
);
1431 return memstream_finalize(&m
, ret
, NULL
);