1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "hostname-util.h"
8 #include "netif-naming-scheme.h"
9 #include "network-generator.h"
10 #include "parse-util.h"
11 #include "proc-cmdline.h"
12 #include "socket-util.h"
13 #include "string-table.h"
14 #include "string-util.h"
19 ip={dhcp|on|any|dhcp6|auto6|either6|link6}
20 ip=<interface>:{dhcp|on|any|dhcp6|auto6|link6}[:[<mtu>][:<macaddr>]]
21 ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|link6|ibft}[:[<mtu>][:<macaddr>]]
22 ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|link6|ibft}[:[<dns1>][:<dns2>]]
23 rd.route=<net>/<netmask>:<gateway>[:<interface>]
24 nameserver=<IP> [nameserver=<IP> ...]
28 ifname=<interface>:<MAC>
29 net.ifname-policy=policy1[,policy2,...][,<MAC>] # This is an original rule, not supported by other tools.
32 vlan=<vlanname>:<phydevice>
33 bond=<bondname>[:<bondslaves>:[:<options>[:<mtu>]]]
34 team=<teammaster>:<teamslaves> # not supported
35 bridge=<bridgename>:<ethnames>
45 static const char * const dracut_dhcp_type_table
[_DHCP_TYPE_MAX
] = {
46 [DHCP_TYPE_NONE
] = "none",
47 [DHCP_TYPE_OFF
] = "off",
48 [DHCP_TYPE_ON
] = "on",
49 [DHCP_TYPE_ANY
] = "any",
50 [DHCP_TYPE_DHCP4
] = "dhcp",
51 [DHCP_TYPE_DHCP6
] = "dhcp6",
52 [DHCP_TYPE_AUTO6
] = "auto6",
53 [DHCP_TYPE_EITHER6
] = "either6",
54 [DHCP_TYPE_IBFT
] = "ibft",
55 [DHCP_TYPE_LINK6
] = "link6",
58 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dracut_dhcp_type
, DHCPType
);
60 static const char * const networkd_dhcp_type_table
[_DHCP_TYPE_MAX
] = {
61 [DHCP_TYPE_NONE
] = "no",
62 [DHCP_TYPE_OFF
] = "no",
63 [DHCP_TYPE_ON
] = "yes",
64 [DHCP_TYPE_ANY
] = "yes",
65 [DHCP_TYPE_DHCP4
] = "ipv4",
66 [DHCP_TYPE_DHCP6
] = "ipv6",
67 [DHCP_TYPE_AUTO6
] = "no", /* TODO: enable other setting? */
68 [DHCP_TYPE_EITHER6
] = "ipv6", /* TODO: enable other setting? */
69 [DHCP_TYPE_IBFT
] = "no",
70 [DHCP_TYPE_LINK6
] = "no",
73 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(networkd_dhcp_type
, DHCPType
);
75 static Address
*address_free(Address
*address
) {
80 LIST_REMOVE(addresses
, address
->network
->addresses
, address
);
82 return mfree(address
);
85 static int address_new(Network
*network
, int family
, unsigned char prefixlen
,
86 union in_addr_union
*addr
, union in_addr_union
*peer
, Address
**ret
) {
91 address
= new(Address
, 1);
95 *address
= (Address
) {
97 .prefixlen
= prefixlen
,
102 LIST_PREPEND(addresses
, network
->addresses
, address
);
104 address
->network
= network
;
111 static Route
*route_free(Route
*route
) {
116 LIST_REMOVE(routes
, route
->network
->routes
, route
);
121 static int route_new(Network
*network
, int family
, unsigned char prefixlen
,
122 union in_addr_union
*dest
, union in_addr_union
*gateway
, Route
**ret
) {
127 route
= new(Route
, 1);
133 .prefixlen
= prefixlen
,
134 .dest
= dest
? *dest
: IN_ADDR_NULL
,
138 LIST_PREPEND(routes
, network
->routes
, route
);
140 route
->network
= network
;
147 static Network
*network_free(Network
*network
) {
154 free(network
->ifname
);
155 free(network
->hostname
);
156 strv_free(network
->dns
);
158 free(network
->bridge
);
161 while ((address
= network
->addresses
))
162 address_free(address
);
164 while ((route
= network
->routes
))
167 return mfree(network
);
170 DEFINE_TRIVIAL_CLEANUP_FUNC(Network
*, network_free
);
172 static int network_new(Context
*context
, const char *name
, Network
**ret
) {
173 _cleanup_(network_freep
) Network
*network
= NULL
;
174 _cleanup_free_
char *ifname
= NULL
;
179 if (!isempty(name
) && !ifname_valid(name
))
182 ifname
= strdup(name
);
186 network
= new(Network
, 1);
190 *network
= (Network
) {
191 .ifname
= TAKE_PTR(ifname
),
192 .dhcp_type
= _DHCP_TYPE_INVALID
,
196 r
= hashmap_ensure_put(&context
->networks_by_name
, &string_hash_ops
, network
->ifname
, network
);
207 Network
*network_get(Context
*context
, const char *ifname
) {
208 return hashmap_get(context
->networks_by_name
, ifname
);
211 static NetDev
*netdev_free(NetDev
*netdev
) {
215 free(netdev
->ifname
);
217 return mfree(netdev
);
220 DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev
*, netdev_free
);
222 static int netdev_new(Context
*context
, const char *_kind
, const char *_ifname
, NetDev
**ret
) {
223 _cleanup_(netdev_freep
) NetDev
*netdev
= NULL
;
224 _cleanup_free_
char *kind
= NULL
, *ifname
= NULL
;
229 if (!ifname_valid(_ifname
))
232 kind
= strdup(_kind
);
236 ifname
= strdup(_ifname
);
240 netdev
= new(NetDev
, 1);
245 .kind
= TAKE_PTR(kind
),
246 .ifname
= TAKE_PTR(ifname
),
249 r
= hashmap_ensure_put(&context
->netdevs_by_name
, &string_hash_ops
, netdev
->ifname
, netdev
);
260 NetDev
*netdev_get(Context
*context
, const char *ifname
) {
261 return hashmap_get(context
->netdevs_by_name
, ifname
);
264 static Link
*link_free(Link
*link
) {
268 free(link
->filename
);
270 strv_free(link
->policies
);
271 strv_free(link
->alt_policies
);
275 DEFINE_TRIVIAL_CLEANUP_FUNC(Link
*, link_free
);
280 const struct hw_addr_data
*mac
,
283 _cleanup_(link_freep
) Link
*link
= NULL
;
284 _cleanup_free_
char *ifname
= NULL
, *filename
= NULL
;
291 if (!ifname_valid(name
))
294 ifname
= strdup(name
);
298 filename
= strdup(name
);
304 filename
= strdup(hw_addr_is_null(mac
) ? "default" :
305 HW_ADDR_TO_STR_FULL(mac
, HW_ADDR_TO_STRING_NO_COLON
));
315 .filename
= TAKE_PTR(filename
),
316 .ifname
= TAKE_PTR(ifname
),
320 r
= hashmap_ensure_put(&context
->links_by_filename
, &string_hash_ops
, link
->filename
, link
);
331 Link
*link_get(Context
*context
, const char *filename
) {
334 return hashmap_get(context
->links_by_filename
, filename
);
337 static int network_set_dhcp_type(Context
*context
, const char *ifname
, const char *dhcp_type
) {
342 t
= dracut_dhcp_type_from_string(dhcp_type
);
346 network
= network_get(context
, ifname
);
348 r
= network_new(context
, ifname
, &network
);
353 network
->dhcp_type
= t
;
357 static int network_set_hostname(Context
*context
, const char *ifname
, const char *hostname
) {
360 network
= network_get(context
, ifname
);
364 return free_and_strdup(&network
->hostname
, hostname
);
367 static int network_set_mtu(Context
*context
, const char *ifname
, int family
, const char *mtu
) {
370 network
= network_get(context
, ifname
);
374 return parse_mtu(family
, mtu
, &network
->mtu
);
377 static int network_set_mac_address(Context
*context
, const char *ifname
, const char *mac
) {
380 network
= network_get(context
, ifname
);
384 return parse_ether_addr(mac
, &network
->mac
);
387 static int network_set_address(Context
*context
, const char *ifname
, int family
, unsigned char prefixlen
,
388 union in_addr_union
*addr
, union in_addr_union
*peer
) {
391 if (!in_addr_is_set(family
, addr
))
394 network
= network_get(context
, ifname
);
398 return address_new(network
, family
, prefixlen
, addr
, peer
, NULL
);
401 static int network_set_route(Context
*context
, const char *ifname
, int family
, unsigned char prefixlen
,
402 union in_addr_union
*dest
, union in_addr_union
*gateway
) {
406 if (!in_addr_is_set(family
, gateway
))
409 network
= network_get(context
, ifname
);
411 r
= network_new(context
, ifname
, &network
);
416 return route_new(network
, family
, prefixlen
, dest
, gateway
, NULL
);
419 static int network_set_dns(Context
*context
, const char *ifname
, const char *dns
) {
420 union in_addr_union a
;
424 r
= in_addr_from_string_auto(dns
, &family
, &a
);
428 network
= network_get(context
, ifname
);
430 r
= network_new(context
, ifname
, &network
);
435 return strv_extend(&network
->dns
, dns
);
438 static int network_set_dhcp_use_dns(Context
*context
, const char *ifname
, bool value
) {
442 network
= network_get(context
, ifname
);
444 r
= network_new(context
, ifname
, &network
);
449 network
->dhcp_use_dns
= value
;
454 static int network_set_vlan(Context
*context
, const char *ifname
, const char *value
) {
458 network
= network_get(context
, ifname
);
460 r
= network_new(context
, ifname
, &network
);
465 return free_and_strdup(&network
->vlan
, value
);
468 static int network_set_bridge(Context
*context
, const char *ifname
, const char *value
) {
472 network
= network_get(context
, ifname
);
474 r
= network_new(context
, ifname
, &network
);
479 return free_and_strdup(&network
->bridge
, value
);
482 static int network_set_bond(Context
*context
, const char *ifname
, const char *value
) {
486 network
= network_get(context
, ifname
);
488 r
= network_new(context
, ifname
, &network
);
493 return free_and_strdup(&network
->bond
, value
);
496 static int parse_cmdline_ip_mtu_mac(Context
*context
, const char *ifname
, int family
, const char *value
) {
500 /* [<mtu>][:<macaddr>] */
502 p
= strchr(value
, ':');
506 mtu
= strndupa_safe(value
, p
- value
);
508 r
= network_set_mtu(context
, ifname
, family
, mtu
);
515 r
= network_set_mac_address(context
, ifname
, p
+ 1);
522 static int parse_ip_address_one(int family
, const char **value
, union in_addr_union
*ret
) {
523 const char *p
= *value
, *q
, *buf
;
531 if (family
== AF_INET6
) {
535 q
= strchr(p
+ 1, ']');
542 buf
= strndupa_safe(p
+ 1, q
- p
- 1);
549 buf
= strndupa_safe(p
, q
- p
);
553 r
= in_addr_from_string(family
, buf
, ret
);
561 static int parse_netmask_or_prefixlen(int family
, const char **value
, unsigned char *ret
) {
562 union in_addr_union netmask
;
566 r
= parse_ip_address_one(family
, value
, &netmask
);
568 if (family
== AF_INET6
)
569 /* TODO: Not supported yet. */
572 *ret
= in4_addr_netmask_to_prefixlen(&netmask
.in
);
574 *ret
= family
== AF_INET6
? 128 : 32;
576 p
= strchr(*value
, ':');
580 q
= strndupa_safe(*value
, p
- *value
);
581 r
= safe_atou8(q
, ret
);
591 static int parse_cmdline_ip_address(Context
*context
, int family
, const char *value
) {
592 union in_addr_union addr
= {}, peer
= {}, gateway
= {};
593 const char *hostname
= NULL
, *ifname
, *dhcp_type
, *dns
, *p
;
594 unsigned char prefixlen
;
597 /* ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[<mtu>][:<macaddr>]]
598 * ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|ibft|link6}[:[<dns1>][:<dns2>]] */
600 r
= parse_ip_address_one(family
, &value
, &addr
);
603 r
= parse_ip_address_one(family
, &value
, &peer
);
606 r
= parse_ip_address_one(family
, &value
, &gateway
);
609 r
= parse_netmask_or_prefixlen(family
, &value
, &prefixlen
);
614 p
= strchr(value
, ':');
619 hostname
= strndupa_safe(value
, p
- value
);
620 if (!hostname_is_valid(hostname
, 0))
627 p
= strchr(value
, ':');
631 ifname
= strndupa_safe(value
, p
- value
);
636 p
= strchr(value
, ':');
640 dhcp_type
= strndupa_safe(value
, p
- value
);
642 r
= network_set_dhcp_type(context
, ifname
, dhcp_type
);
647 r
= network_set_hostname(context
, ifname
, hostname
);
651 r
= network_set_address(context
, ifname
, family
, prefixlen
, &addr
, &peer
);
655 r
= network_set_route(context
, ifname
, family
, 0, NULL
, &gateway
);
662 /* First, try [<mtu>][:<macaddr>] */
663 r
= parse_cmdline_ip_mtu_mac(context
, ifname
, AF_UNSPEC
, p
+ 1);
667 /* Next, try [<dns1>][:<dns2>] */
669 p
= strchr(value
, ':');
671 r
= network_set_dns(context
, ifname
, value
);
675 dns
= strndupa_safe(value
, p
- value
);
676 r
= network_set_dns(context
, ifname
, dns
);
679 r
= network_set_dns(context
, ifname
, p
+ 1);
687 static int parse_cmdline_ip_interface(Context
*context
, const char *value
) {
688 const char *ifname
, *dhcp_type
, *p
;
691 /* ip=<interface>:{dhcp|on|any|dhcp6|auto6|link6}[:[<mtu>][:<macaddr>]] */
693 p
= strchr(value
, ':');
697 ifname
= strndupa_safe(value
, p
- value
);
700 p
= strchr(value
, ':');
704 dhcp_type
= strndupa_safe(value
, p
- value
);
706 r
= network_set_dhcp_type(context
, ifname
, dhcp_type
);
713 return parse_cmdline_ip_mtu_mac(context
, ifname
, AF_UNSPEC
, p
+ 1);
716 static int parse_cmdline_ip(Context
*context
, const char *key
, const char *value
) {
720 if (proc_cmdline_value_missing(key
, value
))
723 p
= strchr(value
, ':');
725 /* ip={dhcp|on|any|dhcp6|auto6|either6|link6} */
726 return network_set_dhcp_type(context
, "", value
);
729 return parse_cmdline_ip_address(context
, AF_INET6
, value
);
731 r
= parse_cmdline_ip_address(context
, AF_INET
, value
);
733 return parse_cmdline_ip_interface(context
, value
);
738 static int parse_cmdline_rd_route(Context
*context
, const char *key
, const char *value
) {
739 union in_addr_union addr
= {}, gateway
= {};
740 unsigned char prefixlen
;
744 /* rd.route=<net>/<netmask>:<gateway>[:<interface>] */
746 if (proc_cmdline_value_missing(key
, value
))
749 if (value
[0] == '[') {
750 p
= strchr(value
, ']');
757 buf
= strndupa_safe(value
+ 1, p
- value
- 1);
761 p
= strchr(value
, ':');
765 buf
= strndupa_safe(value
, p
- value
);
770 r
= in_addr_prefix_from_string(buf
, family
, &addr
, &prefixlen
);
774 p
= strchr(value
, ':');
776 value
= strjoina(value
, ":");
778 r
= parse_ip_address_one(family
, &value
, &gateway
);
782 return network_set_route(context
, value
, family
, prefixlen
, &addr
, &gateway
);
785 static int parse_cmdline_nameserver(Context
*context
, const char *key
, const char *value
) {
786 if (proc_cmdline_value_missing(key
, value
))
789 return network_set_dns(context
, "", value
);
792 static int parse_cmdline_rd_peerdns(Context
*context
, const char *key
, const char *value
) {
795 if (proc_cmdline_value_missing(key
, value
))
796 return network_set_dhcp_use_dns(context
, "", true);
798 r
= parse_boolean(value
);
802 return network_set_dhcp_use_dns(context
, "", r
);
805 static int parse_cmdline_vlan(Context
*context
, const char *key
, const char *value
) {
806 const char *name
, *p
;
810 if (proc_cmdline_value_missing(key
, value
))
813 p
= strchr(value
, ':');
817 name
= strndupa_safe(value
, p
- value
);
819 netdev
= netdev_get(context
, name
);
821 r
= netdev_new(context
, "vlan", name
, &netdev
);
826 return network_set_vlan(context
, p
+ 1, name
);
829 static int parse_cmdline_bridge(Context
*context
, const char *key
, const char *value
) {
830 const char *name
, *p
;
834 if (proc_cmdline_value_missing(key
, value
))
837 p
= strchr(value
, ':');
841 name
= strndupa_safe(value
, p
- value
);
843 netdev
= netdev_get(context
, name
);
845 r
= netdev_new(context
, "bridge", name
, &netdev
);
855 _cleanup_free_
char *word
= NULL
;
857 r
= extract_first_word(&p
, &word
, ",", 0);
861 r
= network_set_bridge(context
, word
, name
);
867 static int parse_cmdline_bond(Context
*context
, const char *key
, const char *value
) {
868 const char *name
, *slaves
, *p
;
872 if (proc_cmdline_value_missing(key
, value
))
875 p
= strchr(value
, ':');
879 name
= strndupa_safe(value
, p
- value
);
881 netdev
= netdev_get(context
, name
);
883 r
= netdev_new(context
, "bond", name
, &netdev
);
889 p
= strchr(value
, ':');
893 slaves
= strndupa_safe(value
, p
- value
);
898 for (const char *q
= slaves
; ; ) {
899 _cleanup_free_
char *word
= NULL
;
901 r
= extract_first_word(&q
, &word
, ",", 0);
907 r
= network_set_bond(context
, word
, name
);
916 p
= strchr(value
, ':');
918 /* TODO: set bonding options */
921 return parse_mtu(AF_UNSPEC
, p
+ 1, &netdev
->mtu
);
924 static int parse_cmdline_ifname(Context
*context
, const char *key
, const char *value
) {
925 struct hw_addr_data mac
;
926 const char *name
, *p
;
929 /* ifname=<interface>:<MAC> */
931 if (proc_cmdline_value_missing(key
, value
))
934 p
= strchr(value
, ':');
938 name
= strndupa_safe(value
, p
- value
);
940 r
= parse_hw_addr(p
+ 1, &mac
);
944 return link_new(context
, name
, &mac
, NULL
);
947 static int parse_cmdline_ifname_policy(Context
*context
, const char *key
, const char *value
) {
948 _cleanup_strv_free_
char **policies
= NULL
, **alt_policies
= NULL
;
949 struct hw_addr_data mac
= HW_ADDR_NULL
;
953 /* net.ifname-policy=policy1[,policy2,...][,<MAC>] */
955 if (proc_cmdline_value_missing(key
, value
))
958 for (const char *q
= value
; ; ) {
959 _cleanup_free_
char *word
= NULL
;
962 r
= extract_first_word(&q
, &word
, ",", 0);
968 p
= name_policy_from_string(word
);
970 r
= parse_hw_addr(word
, &mac
);
974 if (hw_addr_is_null(&mac
))
983 if (alternative_names_policy_from_string(word
) >= 0) {
984 r
= strv_extend(&alt_policies
, word
);
989 r
= strv_consume(&policies
, TAKE_PTR(word
));
994 if (strv_isempty(policies
))
997 r
= link_new(context
, NULL
, &mac
, &link
);
1001 link
->policies
= TAKE_PTR(policies
);
1002 link
->alt_policies
= TAKE_PTR(alt_policies
);
1006 int parse_cmdline_item(const char *key
, const char *value
, void *data
) {
1007 Context
*context
= ASSERT_PTR(data
);
1011 if (streq(key
, "ip"))
1012 return parse_cmdline_ip(context
, key
, value
);
1013 if (streq(key
, "rd.route"))
1014 return parse_cmdline_rd_route(context
, key
, value
);
1015 if (streq(key
, "nameserver"))
1016 return parse_cmdline_nameserver(context
, key
, value
);
1017 if (streq(key
, "rd.peerdns"))
1018 return parse_cmdline_rd_peerdns(context
, key
, value
);
1019 if (streq(key
, "vlan"))
1020 return parse_cmdline_vlan(context
, key
, value
);
1021 if (streq(key
, "bridge"))
1022 return parse_cmdline_bridge(context
, key
, value
);
1023 if (streq(key
, "bond"))
1024 return parse_cmdline_bond(context
, key
, value
);
1025 if (streq(key
, "ifname"))
1026 return parse_cmdline_ifname(context
, key
, value
);
1027 if (streq(key
, "net.ifname-policy"))
1028 return parse_cmdline_ifname_policy(context
, key
, value
);
1033 int context_merge_networks(Context
*context
) {
1034 Network
*all
, *network
;
1039 /* Copy settings about the following options
1040 rd.route=<net>/<netmask>:<gateway>[:<interface>]
1041 nameserver=<IP> [nameserver=<IP> ...]
1044 all
= network_get(context
, "");
1048 if (hashmap_size(context
->networks_by_name
) <= 1)
1051 HASHMAP_FOREACH(network
, context
->networks_by_name
) {
1055 network
->dhcp_use_dns
= all
->dhcp_use_dns
;
1057 r
= strv_extend_strv(&network
->dns
, all
->dns
, false);
1061 LIST_FOREACH(routes
, route
, all
->routes
) {
1062 r
= route_new(network
, route
->family
, route
->prefixlen
, &route
->dest
, &route
->gateway
, NULL
);
1068 assert_se(hashmap_remove(context
->networks_by_name
, "") == all
);
1073 void context_clear(Context
*context
) {
1077 hashmap_free_with_destructor(context
->networks_by_name
, network_free
);
1078 hashmap_free_with_destructor(context
->netdevs_by_name
, netdev_free
);
1079 hashmap_free_with_destructor(context
->links_by_filename
, link_free
);
1082 static int address_dump(Address
*address
, FILE *f
) {
1086 IN_ADDR_PREFIX_TO_STRING(address
->family
, &address
->address
, address
->prefixlen
));
1087 if (in_addr_is_set(address
->family
, &address
->peer
))
1088 fprintf(f
, "Peer=%s\n",
1089 IN_ADDR_TO_STRING(address
->family
, &address
->peer
));
1093 static int route_dump(Route
*route
, FILE *f
) {
1094 fputs("\n[Route]\n", f
);
1095 if (in_addr_is_set(route
->family
, &route
->dest
))
1096 fprintf(f
, "Destination=%s\n",
1097 IN_ADDR_PREFIX_TO_STRING(route
->family
, &route
->dest
, route
->prefixlen
));
1098 fprintf(f
, "Gateway=%s\n",
1099 IN_ADDR_TO_STRING(route
->family
, &route
->gateway
));
1104 void network_dump(Network
*network
, FILE *f
) {
1113 isempty(network
->ifname
) ? "*" : network
->ifname
);
1115 fputs("\n[Link]\n", f
);
1117 if (!ether_addr_is_null(&network
->mac
))
1118 fprintf(f
, "MACAddress=%s\n", ETHER_ADDR_TO_STR(&network
->mac
));
1119 if (network
->mtu
> 0)
1120 fprintf(f
, "MTUBytes=%" PRIu32
"\n", network
->mtu
);
1122 fputs("\n[Network]\n", f
);
1124 dhcp
= networkd_dhcp_type_to_string(network
->dhcp_type
);
1126 fprintf(f
, "DHCP=%s\n", dhcp
);
1128 if (!strv_isempty(network
->dns
))
1129 STRV_FOREACH(dns
, network
->dns
)
1130 fprintf(f
, "DNS=%s\n", *dns
);
1133 fprintf(f
, "VLAN=%s\n", network
->vlan
);
1135 if (network
->bridge
)
1136 fprintf(f
, "Bridge=%s\n", network
->bridge
);
1139 fprintf(f
, "Bond=%s\n", network
->bond
);
1141 fputs("\n[DHCP]\n", f
);
1143 if (!isempty(network
->hostname
))
1144 fprintf(f
, "Hostname=%s\n", network
->hostname
);
1146 if (network
->dhcp_use_dns
>= 0)
1147 fprintf(f
, "UseDNS=%s\n", yes_no(network
->dhcp_use_dns
));
1149 LIST_FOREACH(addresses
, address
, network
->addresses
)
1150 (void) address_dump(address
, f
);
1152 LIST_FOREACH(routes
, route
, network
->routes
)
1153 (void) route_dump(route
, f
);
1156 void netdev_dump(NetDev
*netdev
, FILE *f
) {
1167 if (netdev
->mtu
> 0)
1168 fprintf(f
, "MTUBytes=%" PRIu32
"\n", netdev
->mtu
);
1171 void link_dump(Link
*link
, FILE *f
) {
1175 fputs("[Match]\n", f
);
1177 if (!hw_addr_is_null(&link
->mac
))
1178 fprintf(f
, "MACAddress=%s\n", HW_ADDR_TO_STR(&link
->mac
));
1180 fputs("OriginalName=*\n", f
);
1182 fputs("\n[Link]\n", f
);
1184 if (!isempty(link
->ifname
))
1185 fprintf(f
, "Name=%s\n", link
->ifname
);
1187 if (!strv_isempty(link
->policies
)) {
1188 fputs("NamePolicy=", f
);
1189 fputstrv(f
, link
->policies
, " ", NULL
);
1193 if (!strv_isempty(link
->alt_policies
)) {
1194 fputs("AlternativeNamesPolicy=", f
);
1195 fputstrv(f
, link
->alt_policies
, " ", NULL
);
1200 int network_format(Network
*network
, char **ret
) {
1201 _cleanup_free_
char *s
= NULL
;
1209 _cleanup_fclose_
FILE *f
= NULL
;
1211 f
= open_memstream_unlocked(&s
, &sz
);
1215 network_dump(network
, f
);
1217 /* Add terminating 0, so that the output buffer is a valid string. */
1220 r
= fflush_and_check(f
);
1228 return (int) sz
- 1;
1231 int netdev_format(NetDev
*netdev
, char **ret
) {
1232 _cleanup_free_
char *s
= NULL
;
1240 _cleanup_fclose_
FILE *f
= NULL
;
1242 f
= open_memstream_unlocked(&s
, &sz
);
1246 netdev_dump(netdev
, f
);
1248 /* Add terminating 0, so that the output buffer is a valid string. */
1251 r
= fflush_and_check(f
);
1259 return (int) sz
- 1;
1262 int link_format(Link
*link
, char **ret
) {
1263 _cleanup_free_
char *s
= NULL
;
1271 _cleanup_fclose_
FILE *f
= NULL
;
1273 f
= open_memstream_unlocked(&s
, &sz
);
1279 /* Add terminating 0, so that the output buffer is a valid string. */
1282 r
= fflush_and_check(f
);
1290 return (int) sz
- 1;