On Fri, Feb 20, 2015 at 10:50 AM, Rauta, Alin <alin.ra...@intel.com> wrote: > Hi Tom, Lennart, Zbyszek, > Did you have any chance to look at this patch version ?
I hope to review it this weekend. I might go ahead and implement the DOWN logic independently if that is still an issue (saw your question, but didn't yet look at how you dealt with it in the patch). We need that anyway for manually UP/DOWN of networks. > -----Original Message----- > From: Rauta, Alin > Sent: Tuesday, February 17, 2015 12:07 PM > To: t...@jklm.no; lenn...@poettering.net; zbys...@in.waw.pl > Cc: systemd-devel@lists.freedesktop.org; Kinsella, Ray; Rauta, Alin > Subject: [PATCH v4] Added support for Uplink Failure Detection using > BindCarrier > > --- > man/systemd.network.xml | 11 + > src/libsystemd/sd-network/sd-network.c | 8 + > src/network/networkctl.c | 43 ++-- > src/network/networkd-link.c | 394 > +++++++++++++++++++++++++++++-- > src/network/networkd-link.h | 3 + > src/network/networkd-network-gperf.gperf | 1 + > src/network/networkd-network.c | 1 + > src/network/networkd.h | 2 +- > src/systemd/sd-network.h | 6 + > 9 files changed, 438 insertions(+), 31 deletions(-) > > diff --git a/man/systemd.network.xml b/man/systemd.network.xml index > 485876b..60252e5 100644 > --- a/man/systemd.network.xml > +++ b/man/systemd.network.xml > @@ -280,6 +280,17 @@ > </listitem> > </varlistentry> > <varlistentry> > + <term><varname>BindCarrier=</varname></term> > + <listitem> > + <para>A port or a list of ports. When set, controls the > + behaviour of the current interface. When all ports in the list > + are in an operational down state, the current interface is > brought > + down. When at least one port has carrier, the current interface > + is brought up. > + </para> > + </listitem> > + </varlistentry> > + <varlistentry> > <term><varname>Address=</varname></term> > <listitem> > <para>A static IPv4 or IPv6 address and its prefix length, diff > --git a/src/libsystemd/sd-network/sd-network.c > b/src/libsystemd/sd-network/sd-network.c > index c4713fe..fb5152c 100644 > --- a/src/libsystemd/sd-network/sd-network.c > +++ b/src/libsystemd/sd-network/sd-network.c > @@ -264,6 +264,14 @@ _public_ int sd_network_link_get_domains(int ifindex, > char ***ret) { > return network_get_link_strv("DOMAINS", ifindex, ret); } > > +_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) { > + return network_get_link_strv("CARRIER_BOUND_TO", ifindex, ret); > +} > + > +_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) { > + return network_get_link_strv("CARRIER_BOUND_BY", ifindex, ret); > +} > + > _public_ int sd_network_link_get_wildcard_domain(int ifindex) { > int r; > _cleanup_free_ char *p = NULL, *s = NULL; diff --git > a/src/network/networkctl.c b/src/network/networkctl.c index aa83f32..0637513 > 100644 > --- a/src/network/networkctl.c > +++ b/src/network/networkctl.c > @@ -508,6 +508,8 @@ static int link_status_one( > const char *driver = NULL, *path = NULL, *vendor = NULL, *model = > NULL, *link = NULL; > const char *on_color_operational, *off_color_operational, > *on_color_setup, *off_color_setup; > + _cleanup_strv_free_ char **carrier_bound_to = NULL; > + _cleanup_strv_free_ char **carrier_bound_by = NULL; > struct ether_addr e; > unsigned iftype; > int r, ifindex; > @@ -606,12 +608,15 @@ static int link_status_one( > > sd_network_link_get_network_file(ifindex, &network); > > + sd_network_link_get_carrier_bound_to(ifindex, &carrier_bound_to); > + sd_network_link_get_carrier_bound_by(ifindex, > + &carrier_bound_by); > + > printf("%s%s%s %i: %s\n", on_color_operational, > draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name); > > - printf(" Link File: %s\n" > - "Network File: %s\n" > - " Type: %s\n" > - " State: %s%s%s (%s%s%s)\n", > + printf(" Link File: %s\n" > + " Network File: %s\n" > + " Type: %s\n" > + " State: %s%s%s (%s%s%s)\n", > strna(link), > strna(network), > strna(t), > @@ -619,13 +624,13 @@ static int link_status_one( > on_color_setup, strna(setup_state), off_color_setup); > > if (path) > - printf(" Path: %s\n", path); > + printf(" Path: %s\n", path); > if (driver) > - printf(" Driver: %s\n", driver); > + printf(" Driver: %s\n", driver); > if (vendor) > - printf(" Vendor: %s\n", vendor); > + printf(" Vendor: %s\n", vendor); > if (model) > - printf(" Model: %s\n", model); > + printf(" Model: %s\n", model); > > if (have_mac) { > _cleanup_free_ char *description = NULL; @@ -634,23 +639,29 > @@ static int link_status_one( > ieee_oui(hwdb, &e, &description); > > if (description) > - printf(" HW Address: %s (%s)\n", > ether_addr_to_string(&e, ea), description); > + printf(" HW Address: %s (%s)\n", > ether_addr_to_string(&e, ea), description); > else > - printf(" HW Address: %s\n", > ether_addr_to_string(&e, ea)); > + printf(" HW Address: %s\n", > ether_addr_to_string(&e, ea)); > } > > if (mtu > 0) > - printf(" MTU: %u\n", mtu); > + printf(" MTU: %u\n", mtu); > > - dump_addresses(rtnl, " Address: ", ifindex); > - dump_gateways(rtnl, hwdb, " Gateway: ", ifindex); > + dump_addresses(rtnl, " Address: ", ifindex); > + dump_gateways(rtnl, hwdb, " Gateway: ", ifindex); > > if (!strv_isempty(dns)) > - dump_list(" DNS: ", dns); > + dump_list(" DNS: ", dns); > if (!strv_isempty(domains)) > - dump_list(" Domain: ", domains); > + dump_list(" Domain: ", domains); > if (!strv_isempty(ntp)) > - dump_list(" NTP: ", ntp); > + dump_list(" NTP: ", ntp); > + > + if (!strv_isempty(carrier_bound_to)) > + dump_list("Carrier Bound To: ", carrier_bound_to); > + > + if (!strv_isempty(carrier_bound_by)) > + dump_list("Carrier Bound By: ", carrier_bound_by); > > return 0; > } > diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index > f716e82..d718037 100644 > --- a/src/network/networkd-link.c > +++ b/src/network/networkd-link.c > @@ -275,6 +275,8 @@ static int link_new(Manager *manager, sd_rtnl_message > *message, Link **ret) { > > static void link_free(Link *link) { > Address *address; > + Iterator i; > + Link *carrier; > > if (!link) > return; > @@ -312,6 +314,14 @@ static void link_free(Link *link) { > > udev_device_unref(link->udev_device); > > + HASHMAP_FOREACH (carrier, link->bound_to_links, i) > + hashmap_remove(link->bound_to_links, > INT_TO_PTR(carrier->ifindex)); > + hashmap_free(link->bound_to_links); > + > + HASHMAP_FOREACH (carrier, link->bound_by_links, i) > + hashmap_remove(link->bound_by_links, > INT_TO_PTR(carrier->ifindex)); > + hashmap_free(link->bound_by_links); > + > free(link); > } > > @@ -358,19 +368,6 @@ static void link_set_state(Link *link, LinkState state) { > return; > } > > -void link_drop(Link *link) { > - if (!link || link->state == LINK_STATE_LINGER) > - return; > - > - link_set_state(link, LINK_STATE_LINGER); > - > - log_link_debug(link, "link removed"); > - > - link_unref(link); > - > - return; > -} > - > static void link_enter_unmanaged(Link *link) { > assert(link); > > @@ -1151,13 +1148,319 @@ static int link_up(Link *link) { > return 0; > } > > +static int link_down_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void > *userdata) { > + _cleanup_link_unref_ Link *link = userdata; > + int r; > + > + assert(link); > + > + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) > + return 1; > + > + r = sd_rtnl_message_get_errno(m); > + if (r < 0) > + log_link_warning_errno(link, -r, "%-*s: could not bring > + down interface: %m", IFNAMSIZ, link->ifname); > + > + return 1; > +} > + > +static int link_down(Link *link) { > + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; > + int r; > + > + assert(link); > + assert(link->manager); > + assert(link->manager->rtnl); > + > + log_link_debug(link, "bringing link down"); > + > + r = sd_rtnl_message_new_link(link->manager->rtnl, &req, > + RTM_SETLINK, link->ifindex); > + if (r < 0) { > + log_link_error(link, "Could not allocate RTM_SETLINK > message"); > + return r; > + } > + > + r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP); > + if (r < 0) { > + log_link_error(link, "Could not set link flags: %s", > + strerror(-r)); > + return r; > + } > + > + r = sd_rtnl_call_async(link->manager->rtnl, req, link_down_handler, > link, > + 0, NULL); > + if (r < 0) { > + log_link_error(link, > + "Could not send rtnetlink message: %s", > + strerror(-r)); > + return r; > + } > + > + link_ref(link); > + > + return 0; > +} > + > +static int link_handle_bound_to_list(Link *link) { > + Link *l; > + Iterator i; > + int r; > + bool required_up = false; > + bool link_is_up = false; > + > + assert(link); > + > + if (hashmap_isempty(link->bound_to_links)) > + return 0; > + > + if (link->flags & IFF_UP) > + link_is_up = true; > + > + HASHMAP_FOREACH (l, link->bound_to_links, i) > + if (link_has_carrier(l)) { > + required_up = true; > + break; > + } > + > + if (!required_up && link_is_up) { > + r = link_down(link); > + if (r < 0) > + return r; > + } else if (required_up && !link_is_up) { > + r = link_up(link); > + if (r < 0) > + return r; > + } > + > + return 0; > +} > + > +static int link_handle_bound_by_list(Link *link) { > + Iterator i; > + Link *l; > + int r; > + > + assert(link); > + > + if (hashmap_isempty(link->bound_by_links)) > + return 0; > + > + HASHMAP_FOREACH (l, link->bound_by_links, i) { > + r = link_handle_bound_to_list(l); > + if (r < 0) > + return r; > + } > + > + return 0; > +} > + > +static int link_put_carrier(Link *link, Link *carrier, Hashmap **h) { > + int r; > + > + assert(link); > + assert(carrier); > + > + if (link == carrier) > + return 0; > + > + if (hashmap_get(*h, INT_TO_PTR(carrier->ifindex))) > + return 0; > + > + r = hashmap_ensure_allocated(h, NULL); > + if (r < 0) > + return r; > + > + r = hashmap_put(*h, INT_TO_PTR(carrier->ifindex), carrier); > + if (r < 0) > + return r; > + > + return 0; > +} > + > +static int link_new_bound_by_list(Link *link) { > + Manager *m; > + Link *carrier; > + Iterator i; > + int r; > + bool list_updated = false; > + > + assert(link); > + assert(link->manager); > + > + m = link->manager; > + > + HASHMAP_FOREACH (carrier, m->links, i) { > + if (!carrier->network) > + continue; > + > + if (strv_isempty(carrier->network->bind_carrier)) > + continue; > + > + if (strv_fnmatch(carrier->network->bind_carrier, > link->ifname, 0)) { > + r = link_put_carrier(link, carrier, > &link->bound_by_links); > + if (r < 0) > + return r; > + > + list_updated = true; > + } > + } > + > + if (list_updated) > + link_save(link); > + > + HASHMAP_FOREACH (carrier, link->bound_by_links, i) { > + r = link_put_carrier(carrier, link, > &carrier->bound_to_links); > + if (r < 0) > + return r; > + > + link_save(carrier); > + } > + > + return 0; > +} > + > +static int link_new_bound_to_list(Link *link) { > + Manager *m; > + Link *carrier; > + Iterator i; > + int r; > + bool list_updated = false; > + > + assert(link); > + assert(link->manager); > + > + if (!link->network) > + return 0; > + > + if (strv_isempty(link->network->bind_carrier)) > + return 0; > + > + m = link->manager; > + > + HASHMAP_FOREACH (carrier, m->links, i) { > + if (strv_fnmatch(link->network->bind_carrier, > carrier->ifname, 0)) { > + r = link_put_carrier(link, carrier, > &link->bound_to_links); > + if (r < 0) > + return r; > + > + list_updated = true; > + } > + } > + > + if (list_updated) > + link_save(link); > + > + HASHMAP_FOREACH (carrier, link->bound_to_links, i) { > + r = link_put_carrier(carrier, link, > &carrier->bound_by_links); > + if (r < 0) > + return r; > + > + link_save(carrier); > + } > + > + return 0; > +} > + > +static int link_new_carrier_maps(Link *link) { > + int r; > + > + r = link_new_bound_by_list(link); > + if (r < 0) > + return r; > + > + r = link_handle_bound_by_list(link); > + if (r < 0) > + return r; > + > + r = link_new_bound_to_list(link); > + if (r < 0) > + return r; > + > + r = link_handle_bound_to_list(link); > + if (r < 0) > + return r; > + > + return 0; > +} > + > +static void link_free_bound_to_list(Link *link) { > + Link *bound_to; > + Iterator i; > + > + HASHMAP_FOREACH (bound_to, link->bound_to_links, i) { > + hashmap_remove(link->bound_to_links, > + INT_TO_PTR(bound_to->ifindex)); > + > + if (hashmap_remove(bound_to->bound_by_links, > INT_TO_PTR(link->ifindex))) > + link_save(bound_to); > + } > + > + return; > +} > + > +static void link_free_bound_by_list(Link *link) { > + Link *bound_by; > + Iterator i; > + > + HASHMAP_FOREACH (bound_by, link->bound_by_links, i) { > + hashmap_remove(link->bound_by_links, > + INT_TO_PTR(bound_by->ifindex)); > + > + if (hashmap_remove(bound_by->bound_to_links, > INT_TO_PTR(link->ifindex))) { > + link_save(bound_by); > + link_handle_bound_to_list(bound_by); > + } > + } > + > + return; > +} > + > +static void link_free_carrier_maps(Link *link) { > + bool list_updated = false; > + > + assert(link); > + > + if (!hashmap_isempty(link->bound_to_links)) { > + link_free_bound_to_list(link); > + list_updated = true; > + } > + > + if (!hashmap_isempty(link->bound_by_links)) { > + link_free_bound_by_list(link); > + list_updated = true; > + } > + > + if (list_updated) > + link_save(link); > + > + return; > +} > + > +void link_drop(Link *link) { > + if (!link || link->state == LINK_STATE_LINGER) > + return; > + > + link_set_state(link, LINK_STATE_LINGER); > + > + link_free_carrier_maps(link); > + > + log_link_debug(link, "link removed"); > + > + link_unref(link); > + > + return; > +} > + > static int link_joined(Link *link) { > int r; > > assert(link); > assert(link->network); > > - if (!(link->flags & IFF_UP)) { > + if (!hashmap_isempty(link->bound_to_links)) { > + r = link_handle_bound_to_list(link); > + if (r < 0) > + return r; > + } else if (!(link->flags & IFF_UP)) { > r = link_up(link); > if (r < 0) { > link_enter_failed(link); @@ -1432,6 +1735,14 @@ > static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m, > > log_link_debug(link, "link state is up-to-date"); > > + r = link_new_bound_by_list(link); > + if (r < 0) > + return r; > + > + r = link_handle_bound_by_list(link); > + if (r < 0) > + return r; > + > r = network_get(link->manager, link->udev_device, link->ifname, > &link->mac, &network); > if (r == -ENOENT) { > @@ -1455,6 +1766,10 @@ static int link_initialized_and_synced(sd_rtnl *rtnl, > sd_rtnl_message *m, > if (r < 0) > return r; > > + r = link_new_bound_to_list(link); > + if (r < 0) > + return r; > + > r = link_configure(link); > if (r < 0) > return r; > @@ -1732,6 +2047,10 @@ static int link_carrier_gained(Link *link) { > } > } > > + r = link_handle_bound_by_list(link); > + if (r < 0) > + return r; > + > return 0; > } > > @@ -1746,6 +2065,10 @@ static int link_carrier_lost(Link *link) { > return r; > } > > + r = link_handle_bound_by_list(link); > + if (r < 0) > + return r; > + > return 0; > } > > @@ -1785,16 +2108,26 @@ int link_update(Link *link, sd_rtnl_message *m) { > link_ref(link); > log_link_info(link, "link readded"); > link_set_state(link, LINK_STATE_ENSLAVING); > + > + r = link_new_carrier_maps(link); > + if (r < 0) > + return r; > } > > r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname); > if (r >= 0 && !streq(ifname, link->ifname)) { > log_link_info(link, "renamed to %s", ifname); > > + link_free_carrier_maps(link); > + > free(link->ifname); > link->ifname = strdup(ifname); > if (!link->ifname) > return -ENOMEM; > + > + r = link_new_carrier_maps(link); > + if (r < 0) > + return r; > } > > r = sd_rtnl_message_read_u32(m, IFLA_MTU, &mtu); @@ -2063,6 +2396,39 > @@ int link_save(Link *link) { > llmnr_support_to_string(link->network->llmnr)); > } > > + if (!hashmap_isempty(link->bound_to_links)) { > + Link *carrier; > + Iterator i; > + bool space = false; > + > + fputs("CARRIER_BOUND_TO=", f); > + HASHMAP_FOREACH(carrier, link->bound_to_links, i) { > + if (space) > + fputc(' ', f); > + fputs(carrier->ifname, f); > + space = true; > + } > + > + fputs("\n", f); > + } > + > + if (!hashmap_isempty(link->bound_by_links)) { > + Link *carrier; > + Iterator i; > + bool space = false; > + > + fputs("CARRIER_BOUND_BY=", f); > + space = false; > + HASHMAP_FOREACH(carrier, link->bound_by_links, i) { > + if (space) > + fputc(' ', f); > + fputs(carrier->ifname, f); > + space = true; > + } > + > + fputs("\n", f); > + } > + > if (link->dhcp_lease) { > assert(link->network); > > diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index > cec158e..479098c 100644 > --- a/src/network/networkd-link.h > +++ b/src/network/networkd-link.h > @@ -85,6 +85,9 @@ struct Link { > > sd_lldp *lldp; > char *lldp_file; > + > + Hashmap *bound_by_links; > + Hashmap *bound_to_links; > }; > > Link *link_unref(Link *link); > diff --git a/src/network/networkd-network-gperf.gperf > b/src/network/networkd-network-gperf.gperf > index fc277df..b0c23a7 100644 > --- a/src/network/networkd-network-gperf.gperf > +++ b/src/network/networkd-network-gperf.gperf > @@ -48,6 +48,7 @@ Network.LLMNR, config_parse_llmnr, > 0, > Network.NTP, config_parse_strv, 0, > offsetof(Network, ntp) > Network.IPForward, config_parse_address_family_boolean,0, > offsetof(Network, ip_forward) > Network.IPMasquerade, config_parse_bool, 0, > offsetof(Network, ip_masquerade) > +Network.BindCarrier, config_parse_strv, 0, > offsetof(Network, bind_carrier) > Address.Address, config_parse_address, 0, > 0 > Address.Peer, config_parse_address, 0, > 0 > Address.Broadcast, config_parse_broadcast, 0, > 0 > diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c > index 35ac064..3be993c 100644 > --- a/src/network/networkd-network.c > +++ b/src/network/networkd-network.c > @@ -209,6 +209,7 @@ void network_free(Network *network) { > strv_free(network->ntp); > strv_free(network->dns); > strv_free(network->domains); > + strv_free(network->bind_carrier); > > netdev_unref(network->bridge); > > diff --git a/src/network/networkd.h b/src/network/networkd.h index > bdb2f20..e75746f 100644 > --- a/src/network/networkd.h > +++ b/src/network/networkd.h > @@ -151,7 +151,7 @@ struct Network { > Hashmap *fdb_entries_by_section; > > bool wildcard_domain; > - char **domains, **dns, **ntp; > + char **domains, **dns, **ntp, **bind_carrier; > > LLMNRSupport llmnr; > > diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index > 027730d..4d96c86 100644 > --- a/src/systemd/sd-network.h > +++ b/src/systemd/sd-network.h > @@ -116,6 +116,12 @@ int sd_network_link_get_lldp(int ifindex, char **lldp); > /* Get the DNS domain names for a given link. */ int > sd_network_link_get_domains(int ifindex, char ***domains); > > +/* Get the CARRIERS to which current link is bound to. */ int > +sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers); > + > +/* Get the CARRIERS that are bound to current link. */ int > +sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers); > + > /* Returns whether or not domains that don't match any link should be > resolved > * on this link. 1 for yes, 0 for no and negative value for error */ int > sd_network_link_get_wildcard_domain(int ifindex); > -- > 1.9.3 > _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel