[systemd-devel] [PATCH] Added Uplink failure detection feature to networkd

Alin Rauta alin.rauta at intel.com
Fri Jan 23 09:20:30 PST 2015


---
 Makefile.am                             |    4 +
 man/systemd.netdev.xml                  |   72 +-
 src/libsystemd/sd-network/sd-network.c  |  117 +++
 src/network/networkctl.c                |  153 ++++
 src/network/networkd-link.c             |   35 +
 src/network/networkd-manager.c          |   36 +
 src/network/networkd-netdev-gperf.gperf |    3 +
 src/network/networkd-netdev-ufd-group.c |  298 +++++++
 src/network/networkd-netdev-ufd-group.h |   85 ++
 src/network/networkd-netdev.c           |   36 +
 src/network/networkd-netdev.h           |    6 +
 src/network/networkd-ufd-daemon.c       | 1321 +++++++++++++++++++++++++++++++
 src/network/networkd-ufd-daemon.h       |   34 +
 src/network/networkd.c                  |    7 +
 src/network/networkd.h                  |    6 +
 src/systemd/sd-network.h                |   20 +
 16 files changed, 2231 insertions(+), 2 deletions(-)
 create mode 100644 src/network/networkd-netdev-ufd-group.c
 create mode 100644 src/network/networkd-netdev-ufd-group.h
 create mode 100644 src/network/networkd-ufd-daemon.c
 create mode 100644 src/network/networkd-ufd-daemon.h

diff --git a/Makefile.am b/Makefile.am
index 45d7a34..604173b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5575,6 +5575,8 @@ libsystemd_networkd_core_la_SOURCES = \
 	src/network/networkd-netdev-tuntap.h \
 	src/network/networkd-netdev-bond.h \
 	src/network/networkd-netdev-bridge.h \
+	src/network/networkd-netdev-ufd-group.h \
+	src/network/networkd-ufd-daemon.h \
 	src/network/networkd-netdev.c \
 	src/network/networkd-netdev-tunnel.c \
 	src/network/networkd-netdev-veth.c \
@@ -5586,6 +5588,8 @@ libsystemd_networkd_core_la_SOURCES = \
 	src/network/networkd-netdev-tuntap.c \
 	src/network/networkd-netdev-bond.c \
 	src/network/networkd-netdev-bridge.c \
+	src/network/networkd-netdev-ufd-group.c \
+	src/network/networkd-ufd-daemon.c \
 	src/network/networkd-link.c \
 	src/network/networkd-ipv4ll.c \
 	src/network/networkd-dhcp4.c \
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index 7edec36..3c60441 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -168,8 +168,8 @@
                                                 <literal>ipip</literal>, <literal>gre</literal>,
                                                 <literal>gretap</literal>, <literal>sit</literal>,
                                                 <literal>vti</literal>, <literal>veth</literal>,
-                                                <literal>tun</literal>, <literal>tap</literal> and
-                                                <literal>dummy</literal>
+                                                <literal>tun</literal>, <literal>tap</literal>,
+                                                <literal>ufd</literal> and <literal>dummy</literal>
                                                 are supported. This option is compulsory.</para>
                                         </listitem>
                                 </varlistentry>
@@ -553,6 +553,52 @@
         </refsect1>
 
         <refsect1>
+                <title>[UFDGroup] Section Options</title>
+
+                        <para>The <literal>[UFDGroup]</literal> section is used to define uplink failure detection group parameters.
+                        The section only applies for netdevs of kind <literal>ufd</literal>, and accepts the following key:</para>
+
+                        <variablelist class='network-directives'>
+
+                                <varlistentry>
+                                        <term><varname>Id=</varname></term>
+                                        <listitem>
+                                                <para>Uplink failure detection group Id. This option is compulsory.</para>
+                                        </listitem>
+                                </varlistentry>
+                        </variablelist>
+        </refsect1>
+
+        <refsect1>
+                <title>[UFDLink] Section Options</title>
+
+                        <para>The <literal>[UFDLink]</literal> section is used to define one or more uplink failure detection links.
+                        The section only applies for netdevs of kind <literal>ufd</literal>, and accepts the following key:</para>
+
+                        <variablelist class='network-directives'>
+
+                                <varlistentry>
+                                        <term><varname>Name=</varname></term>
+                                        <listitem>
+                                                <para>An interface name or an enumeration of interface names separated by comma.
+                                                This option is compulsory.</para>
+                                        </listitem>
+                                </varlistentry>
+
+                                <varlistentry>
+                                        <term><varname>Type=</varname></term>
+                                        <listitem>
+                                                <para>A string defining the link(s) type.
+                                                It can only take the following string values: <literal>uplink</literal>
+                                                or <literal>downlink</literal>. This option is compulsory.</para>
+                                        </listitem>
+                                </varlistentry>
+
+                        </variablelist>
+
+        </refsect1>
+
+        <refsect1>
                 <title>Example</title>
                 <example>
                         <title>/etc/systemd/network/bridge.netdev</title>
@@ -645,6 +691,28 @@ Name=veth-peer</programlisting>
                 </example>
 
                 <example>
+                        <title>/etc/systemd/network/ufd.netdev</title>
+                        <programlisting>[NetDev]
+Name=group1
+Kind=ufd
+
+[UFDGroup]
+Id=45
+
+[UFDLink]
+Name=sw0p5,sw0p10
+Type=uplink
+
+[UFDLink]
+Name=sw0p1
+Type=uplink
+
+[UFDLink]
+Name=sw0p2
+Type=downlink</programlisting>
+                </example>
+
+                <example>
                         <title>/etc/systemd/network/dummy.netdev</title>
                         <programlisting>[NetDev]
 Name=dummy-test
diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c
index c735cac..d765c97 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -368,3 +368,120 @@ _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *tim
         *timeout_usec = (uint64_t) -1;
         return 0;
 }
+
+_public_ int sd_network_ufd_get_setup_state(int group_id, char **state) {
+        _cleanup_free_ char *s = NULL, *p = NULL;
+        int r;
+
+        assert_return(state, -EINVAL);
+
+        if (asprintf(&p, "/run/systemd/netif/ufd/groups/%d", group_id) < 0)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, "GROUP_STATE", &s, NULL);
+        if (r == -ENOENT)
+                return -ENODATA;
+        if (r < 0)
+                return r;
+        if (isempty(s))
+                return -ENODATA;
+
+        *state = s;
+        s = NULL;
+
+        return 0;
+}
+
+_public_ int sd_network_ufd_get_config_file(int group_id, char **filename) {
+        _cleanup_free_ char *s = NULL, *p = NULL;
+        int r;
+
+        assert_return(filename, -EINVAL);
+
+        if (asprintf(&p, "/run/systemd/netif/ufd/groups/%d", group_id) < 0)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, "CONFIG_FILE", &s, NULL);
+        if (r == -ENOENT)
+                return -ENODATA;
+        if (r < 0)
+                return r;
+        if (isempty(s))
+                return -ENODATA;
+
+        *filename = s;
+        s = NULL;
+
+        return 0;
+}
+
+static int network_get_ufd_strv(const char *key, int group_id, char ***ret) {
+        _cleanup_free_ char *p = NULL, *s = NULL;
+        _cleanup_strv_free_ char **a = NULL;
+        int r;
+
+        assert_return(ret, -EINVAL);
+
+        if (asprintf(&p, "/run/systemd/netif/ufd/groups/%d", group_id) < 0)
+                return -ENOMEM;
+
+        r = parse_env_file(p, NEWLINE, key, &s, NULL);
+        if (r == -ENOENT)
+                return -ENODATA;
+        if (r < 0)
+                return r;
+        if (isempty(s)) {
+                *ret = NULL;
+                return 0;
+        }
+
+        a = strv_split(s, " ");
+        if (!a)
+                return -ENOMEM;
+
+        strv_uniq(a);
+        r = strv_length(a);
+
+        *ret = a;
+        a = NULL;
+
+        return r;
+}
+
+_public_ int sd_network_ufd_get_uplinks(int group_id, char ***ret) {
+        return network_get_ufd_strv("UPLINKS", group_id, ret);
+}
+
+_public_ int sd_network_ufd_get_downlinks(int group_id, char ***ret) {
+        return network_get_ufd_strv("DOWNLINKS", group_id, ret);
+}
+
+_public_ int sd_network_ufd_get_group_list(char ***ret) {
+        _cleanup_free_ char *p = NULL, *s = NULL;
+        _cleanup_strv_free_ char **a = NULL;
+        int r;
+
+        assert_return(ret, -EINVAL);
+
+        r = parse_env_file("/run/systemd/netif/ufd/state", NEWLINE, "GROUP_LIST", &s, NULL);
+        if (r == -ENOENT)
+                return -ENODATA;
+        if (r < 0)
+                return r;
+        if (isempty(s)) {
+                *ret = NULL;
+                return 0;
+        }
+
+        a = strv_split(s, " ");
+        if (!a)
+                return -ENOMEM;
+
+        strv_uniq(a);
+        r = strv_length(a);
+
+        *ret = a;
+        a = NULL;
+
+        return 0;
+}
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index aa83f32..89633b4 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -1008,6 +1008,157 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
         return 0;
 }
 
+static int ufd_show_one(int group_id) {
+        _cleanup_free_ char *setup_state = NULL;
+        _cleanup_free_ char *config_file = NULL;
+        _cleanup_strv_free_ char **up_links = NULL;
+        _cleanup_strv_free_ char **down_links = NULL;
+        const char *green;
+        const char *yellow;
+        const char *off_color;
+        int r;
+
+        green = ansi_highlight_green();
+        yellow = ansi_highlight_yellow();
+        off_color = ansi_highlight_off();
+
+        r = sd_network_ufd_get_setup_state(group_id, &setup_state);
+        if (r < 0) {
+                log_error("UFD group: %d not found or problems reading UFD files", group_id);
+                return r;
+        }
+
+        sd_network_ufd_get_config_file(group_id, &config_file);
+        sd_network_ufd_get_uplinks(group_id, &up_links);
+        sd_network_ufd_get_downlinks(group_id, &down_links);
+
+        printf("%s%s%s %s: %d\n",
+               green, draw_special_char(DRAW_BLACK_CIRCLE), off_color, "UFD Group", group_id);
+
+        printf("Config File: %s\n"
+               "      State: %s%s%s\n",
+               strna(config_file),
+               green, strna(setup_state), off_color);
+
+        printf("    Uplinks:\n");
+
+        if (!strv_isempty(up_links)) {
+                char **i;
+
+                STRV_FOREACH(i, up_links) {
+                        char ifname[IF_NAMESIZE+1] = "";
+                        int ifindex = atoi(*i);
+
+                        if (ifindex > 0)
+                                printf("           %s%s%s %d: ",
+                                       yellow, draw_special_char(DRAW_ARROW), off_color, ifindex);
+
+                        if (if_indextoname(ifindex, ifname))
+                                printf("%s", ifname);
+
+                        printf("\n");
+                }
+        }
+        else
+                printf("            List is empty\n");
+
+        printf("  Downlinks:\n");
+
+        if (!strv_isempty(down_links)) {
+                char **i;
+
+                STRV_FOREACH(i, down_links) {
+                        char ifname[IF_NAMESIZE+1] = "";
+                        int ifindex = atoi(*i);
+
+                        if (ifindex > 0)
+                                printf("           %s%s%s %d: ",
+                                       yellow, draw_special_char(DRAW_ARROW), off_color, ifindex);
+
+                        if (if_indextoname(ifindex, ifname))
+                                printf("%s", ifname);
+
+                        printf("\n");
+                }
+        }
+        else
+                printf("            List is empty\n");
+
+        return 0;
+}
+
+static int ufd_show(int argc, char *argv[], void *userdata) {
+        char **in_arg;
+        int r;
+
+        if (argc <= 1 && !arg_all) {
+                _cleanup_strv_free_ char **group_list = NULL;
+
+                 sd_network_ufd_get_group_list(&group_list);
+
+                 if (!strv_isempty(group_list)) {
+                         char **i;
+
+                         STRV_FOREACH(i, group_list) {
+                                 const char *on_color = ansi_highlight_green();
+                                 const char *off_color = ansi_highlight_off();
+
+                                 printf("%s%s%s %s: %s\n",
+                                        on_color, draw_special_char(DRAW_BLACK_CIRCLE), off_color, "UFD Group", *i);
+                         }
+                 }
+                 else
+                         printf("UFD Group list is empty\n");
+        }
+
+        if (arg_all) {
+                _cleanup_strv_free_ char **group_list = NULL;
+
+                sd_network_ufd_get_group_list(&group_list);
+
+                 if (!strv_isempty(group_list)) {
+                         char **i;
+                         bool first = true;
+
+                         STRV_FOREACH(i, group_list) {
+                                 int group_id;
+
+                                 group_id = atoi(*i);
+
+                                 if (!first)
+                                         fputc('\n', stdout);
+
+                                 first = false;
+
+                                 r = ufd_show_one(group_id);
+                                 if (r < 0) {
+                                         log_error("UFD: Failed to print info");
+                                         return r;
+                                 }
+                         }
+                 }
+                 else
+                         printf("UFD Group list is empty\n");
+        }
+
+        STRV_FOREACH(in_arg, argv + 1) {
+                int group_id;
+
+                if (in_arg != argv + 1)
+                        fputc('\n', stdout);
+
+                group_id = atoi(*in_arg);
+
+                r = ufd_show_one(group_id);
+                if (r < 0) {
+                        log_error("UFD: Failed to print info");
+                        return r;
+                }
+        }
+
+        return 0;
+}
+
 static void help(void) {
         printf("%s [OPTIONS...]\n\n"
                "Query and control the networking subsystem.\n\n"
@@ -1020,6 +1171,7 @@ static void help(void) {
                "  list                  List links\n"
                "  status [LINK...]      Show link status\n"
                "  lldp                  Show lldp information\n"
+               "  ufd [GROUP_ID...]     Show Uplink failure detection groups\n"
                , program_invocation_short_name);
 }
 
@@ -1086,6 +1238,7 @@ static int networkctl_main(int argc, char *argv[]) {
                 { "list", VERB_ANY, 1, VERB_DEFAULT, list_links },
                 { "status", 1, VERB_ANY, 0, link_status },
                 { "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status },
+                { "ufd", 1, VERB_ANY, 0, ufd_show },
                 {}
         };
 
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 310eb6c..9ea9ea8 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -575,6 +575,18 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         if (link->link_messages == 0) {
                 log_link_debug(link, "routes set");
                 link->static_configured = true;
+
+                /* this link is now static configured,
+                   so decrease the number of links that needs to be configured. */
+                link->manager->links_to_configure --;
+
+                /* check if all links are configured. If yes, start configuring the groups. */
+                if ((0 == link->manager->links_to_configure) && (false == link->manager->groups_configured)) {
+                        r = manager_enumerate_groups(link->manager);
+                        if(r < 0)
+                                log_error("Could not enumerate groups error: %s", strerror(-r));
+                }
+
                 link_client_handler(link);
         }
 
@@ -606,6 +618,18 @@ static int link_enter_set_routes(Link *link) {
 
         if (link->link_messages == 0) {
                 link->static_configured = true;
+
+                /* this link is now static configured,
+                   so decrease the number of links that needs to be configured. */
+                link->manager->links_to_configure --;
+
+                /* check if all links are configured. If yes, start configuring the groups. */
+                if ((0 == link->manager->links_to_configure) && (false == link->manager->groups_configured)) {
+                        r = manager_enumerate_groups(link->manager);
+                        if(r < 0)
+                                log_error("Could not enumerate groups error: %s", strerror(-r));
+                }
+
                 link_client_handler(link);
         } else
                 log_link_debug(link, "setting routes");
@@ -1377,6 +1401,17 @@ static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m,
                         &link->mac, &network);
         if (r == -ENOENT) {
                 link_enter_unmanaged(link);
+
+                /* this link is unmanaged,
+                   so decrease the number of links that needs to be configured. */
+                link->manager->links_to_configure --;
+
+                /* check if all links are configured. If yes, start configuring the groups. */
+                if ((0 == link->manager->links_to_configure) && (false == link->manager->groups_configured)) {
+                        r = manager_enumerate_groups(link->manager);
+                        if(r < 0)
+                                log_error("Could not enumerate groups error: %s", strerror(-r));
+                }
                 return 1;
         } else if (r < 0)
                 return r;
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 4c90434..8423adb 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -83,6 +83,9 @@ int manager_new(Manager **ret) {
         if (!m)
                 return -ENOMEM;
 
+        m->links_to_configure = 0;
+        m->groups_configured = false;
+
         m->state_file = strdup("/run/systemd/netif/state");
         if (!m->state_file)
                 return -ENOMEM;
@@ -126,6 +129,10 @@ int manager_new(Manager **ret) {
         if (!m->netdevs)
                 return -ENOMEM;
 
+        m->group_netdevs = hashmap_new(&string_hash_ops);
+        if (!m->netdevs)
+                return -ENOMEM;
+
         LIST_HEAD_INIT(m->networks);
 
         r = setup_default_address_pool(m);
@@ -143,6 +150,7 @@ void manager_free(Manager *m) {
         NetDev *netdev;
         Link *link;
         AddressPool *pool;
+        Iterator i;
 
         if (!m)
                 return;
@@ -162,6 +170,15 @@ void manager_free(Manager *m) {
         while ((network = m->networks))
                 network_free(network);
 
+        /* Close groups. */
+        netdev_clear_groups();
+
+        HASHMAP_FOREACH(netdev, m->group_netdevs, i) {
+                hashmap_remove(m->group_netdevs, netdev->ifname);
+                netdev_unref(netdev);
+        }
+        hashmap_free(m->group_netdevs);
+
         while ((netdev = hashmap_first(m->netdevs)))
                 netdev_unref(netdev);
         hashmap_free(m->netdevs);
@@ -306,6 +323,23 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
         return 1;
 }
 
+int manager_enumerate_groups(Manager *m) {
+        NetDev *netdev;
+        Iterator i;
+        int r;
+        int k = 0;
+
+        m->groups_configured = true;
+
+        HASHMAP_FOREACH(netdev, m->group_netdevs, i) {
+                r = netdev_create_group(netdev);
+                if (r < 0)
+                         k = r;
+        }
+
+        return k;
+}
+
 int manager_rtnl_enumerate_links(Manager *m) {
         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
         sd_rtnl_message *link;
@@ -329,6 +363,8 @@ int manager_rtnl_enumerate_links(Manager *m) {
         for (link = reply; link; link = sd_rtnl_message_next(link)) {
                 int k;
 
+                m->links_to_configure ++;
+
                 k = manager_rtnl_process_link(m->rtnl, link, m);
                 if (k < 0)
                         r = k;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 963c47c..27d3d48 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -64,3 +64,6 @@ Bond.LACPTransmitRate,    config_parse_bond_lacp_rate,        0,
 Bond.MIIMonitorSec,       config_parse_sec,                   0,                             offsetof(Bond, miimon)
 Bond.UpDelaySec,          config_parse_sec,                   0,                             offsetof(Bond, updelay)
 Bond.DownDelaySec,        config_parse_sec,                   0,                             offsetof(Bond, downdelay)
+UFDGroup.Id,              config_parse_int,                   0,                             offsetof(UfdGroup, id)
+UFDLink.Name,             config_parse_ufd_link_name,         0,                             0
+UFDLink.Type,             config_parse_ufd_link_type,         0,                             0
diff --git a/src/network/networkd-netdev-ufd-group.c b/src/network/networkd-netdev-ufd-group.c
new file mode 100644
index 0000000..9571c3d
--- /dev/null
+++ b/src/network/networkd-netdev-ufd-group.c
@@ -0,0 +1,298 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+    This file is part of systemd.
+
+    Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+    systemd is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    systemd is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "missing.h"
+#include "conf-parser.h"
+#include "network-internal.h"
+#include "networkd-ufd-daemon.h"
+#include "networkd-netdev-ufd-group.h"
+
+static const char* const ufd_type_table[_UFD_TYPE_MAX] = {
+        [UFD_TYPE_UP_LINK] = "uplink",
+        [UFD_TYPE_DOWN_LINK] = "downlink",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(ufd_type, UfdType);
+
+/* clears previous UFD configuration. */
+void ufd_groups_clear(void) {
+        return ufd_daemon_close();
+}
+
+static void ufd_group_init(NetDev *n) {
+        UfdGroup *ufd = UFDGROUP(n);
+
+        assert(n);
+        assert(ufd);
+
+        /* init the list of links and the hashmap. */
+        LIST_HEAD_INIT(ufd->links);
+
+        ufd->ufd_links_by_section = hashmap_new(NULL);
+        if (!ufd->ufd_links_by_section)
+                log_error("UFD: Failed to create hashmap for UFD groups");
+}
+
+static int add_link_to_list(const char *const link_name,
+                            char **ret) {
+        size_t len;
+        char *links = *ret;
+
+        assert(link_name);
+
+        len = strlen(link_name);
+
+        if (!links) {
+                links = malloc(len + 1);
+                if (!links)
+                        return -ENOMEM;
+
+                strncpy(links, link_name, len + 1);
+        }
+        else {
+                links = realloc(links, strlen(links) + len + 2);
+                if (!links)
+                        return -ENOMEM;
+
+                strncat(links, ",", 1);
+                strncat(links, link_name, len);
+        }
+
+        *ret = links;
+
+        return 0;
+}
+
+static int netdev_create_ufd_group(NetDev *netdev) {
+        UfdGroup *ufd_group = UFDGROUP(netdev);
+        UfdLink *ufd_link;
+        char *up_links = NULL;
+        char *down_links = NULL;
+        int r;
+
+        assert(netdev);
+        assert(ufd_group);
+
+        r = ufd_daemon_init();
+        if (r < 0)
+                return r;
+
+        LIST_FOREACH(links, ufd_link, ufd_group->links) {
+                switch (ufd_link->type) {
+                case UFD_TYPE_UP_LINK:
+                        r = add_link_to_list(ufd_link->name, &up_links);
+                        if (r < 0) {
+                                free(up_links);
+                                free(down_links);
+                                return r;
+                        }
+
+                        break;
+
+                case UFD_TYPE_DOWN_LINK:
+                        r = add_link_to_list(ufd_link->name, &down_links);
+                        if (r < 0) {
+                                free(up_links);
+                                free(down_links);
+                                return r;
+                        }
+
+                        break;
+
+                default:
+                        assert_not_reached("UFD: Received invalid UFD link type.");
+                }
+        }
+
+        r = ufd_daemon_set_group(ufd_group->id, netdev->filename, up_links, down_links);
+        if (r < 0)
+                log_error("UFD: Could not set Uplink failure detection group Id: %d error: %s",
+                          ufd_group->id, strerror(-r));
+        else
+                log_debug("UFD: Created uplink failure detection group Id: %d", ufd_group->id);
+
+        free(up_links);
+        free(down_links);
+
+        return r;
+}
+
+static int ufd_link_new_static(UfdGroup *const ufd_group,
+                               const unsigned section,
+                               UfdLink **ret) {
+        _cleanup_ufdlink_free_ UfdLink *ufd_link = NULL;
+
+        assert(ufd_group);
+
+        /* check if the hashmap exists. */
+        if (!ufd_group->ufd_links_by_section)
+                return -ENOMEM;
+
+        /* search entry in hashmap first. */
+        if (section) {
+                ufd_link = hashmap_get(ufd_group->ufd_links_by_section, UINT_TO_PTR(section));
+                if (ufd_link) {
+                        *ret = ufd_link;
+                        ufd_link = NULL;
+
+                        return 0;
+                }
+        }
+
+        ufd_link = new0(UfdLink, 1);
+        if (!ufd_link)
+                return -ENOMEM;
+
+        ufd_link->group = ufd_group;
+
+        LIST_PREPEND(links, ufd_group->links, ufd_link);
+
+        if (section) {
+                ufd_link->section = section;
+                hashmap_put(ufd_group->ufd_links_by_section,
+                            UINT_TO_PTR(ufd_link->section), ufd_link);
+        }
+
+        *ret = ufd_link;
+        ufd_link = NULL;
+
+        return 0;
+}
+
+
+void ufd_link_free(UfdLink *ufd_link) {
+        if (!ufd_link)
+                return;
+
+        if (ufd_link->group) {
+                LIST_REMOVE(links, ufd_link->group->links, ufd_link);
+
+                if (ufd_link->section)
+                    hashmap_remove(ufd_link->group->ufd_links_by_section,
+                                   UINT_TO_PTR(ufd_link->section));
+        }
+
+        free(ufd_link->name);
+
+        free(ufd_link);
+}
+
+static void ufd_group_done(NetDev *n) {
+        UfdGroup *ufd = UFDGROUP(n);
+        UfdLink *ufd_link;
+
+        assert(n);
+        assert(ufd);
+
+        while ((ufd_link = ufd->links))
+                ufd_link_free(ufd_link);
+
+        hashmap_free(ufd->ufd_links_by_section);
+}
+
+int config_parse_ufd_link_name(const char *unit,
+                               const char *filename,
+                               unsigned line,
+                               const char *section,
+                               unsigned section_line,
+                               const char *lvalue,
+                               int ltype,
+                               const char *rvalue,
+                               void *data,
+                               void *userdata) {
+        UfdGroup *ufd_group = userdata;
+        _cleanup_ufdlink_free_ UfdLink *ufd_link = NULL;
+        int r;
+
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = ufd_link_new_static(ufd_group, section_line, &ufd_link);
+        if (r < 0) {
+                log_error("UFD: Failed to allocate a new ufd_link: %s", strerror(-r));
+                return r;
+        }
+
+        r = config_parse_string(unit, filename, line, section,
+                                section_line, lvalue, ltype,
+                                rvalue, &ufd_link->name, userdata);
+        if (r < 0) {
+                log_error("UFD: Failed to parse ufd_link name: %s", strerror(-r));
+                return r;
+        }
+
+        ufd_link = NULL;
+
+        return 0;
+}
+
+int config_parse_ufd_link_type(const char *unit,
+                               const char *filename,
+                               unsigned line,
+                               const char *section,
+                               unsigned section_line,
+                               const char *lvalue,
+                               int ltype,
+                               const char *rvalue,
+                               void *data,
+                               void *userdata) {
+        UfdGroup *ufd_group = userdata;
+        UfdType type;
+        _cleanup_ufdlink_free_ UfdLink *ufd_link = NULL;
+        int r;
+
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = ufd_link_new_static(ufd_group, section_line, &ufd_link);
+        if (r < 0) {
+                log_error("UFD: Failed to allocate a new ufd_link: %s", strerror(-r));
+                return r;
+        }
+
+        if ((type = ufd_type_from_string(rvalue)) < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, -type,
+                           "UFD: Failed to parse Ufd type, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        ufd_link->type = type;
+
+        ufd_link = NULL;
+
+        return 0;
+}
+
+const NetDevVTable ufd_group_vtable = {
+        .object_size = sizeof(UfdGroup),
+        .init = ufd_group_init,
+        .sections = "Match\0NetDev\0UFDGroup\0UFDLink\0",
+        .done = ufd_group_done,
+        .create_type = NETDEV_CREATE_GROUP,
+        .create = netdev_create_ufd_group,
+};
diff --git a/src/network/networkd-netdev-ufd-group.h b/src/network/networkd-netdev-ufd-group.h
new file mode 100644
index 0000000..f792142
--- /dev/null
+++ b/src/network/networkd-netdev-ufd-group.h
@@ -0,0 +1,85 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+typedef struct UfdGroup UfdGroup;
+typedef struct UfdLink UfdLink;
+
+#include "networkd-netdev.h"
+
+typedef enum UfdType {
+        UFD_TYPE_UP_LINK,
+        UFD_TYPE_DOWN_LINK,
+        _UFD_TYPE_MAX,
+        _UFD_TYPE_INVALID = -1
+}UfdType;
+
+struct UfdLink {
+        char *name;
+        UfdGroup *group;
+
+        unsigned section;
+        UfdType type;
+        LIST_FIELDS(UfdLink, links);
+};
+
+struct UfdGroup {
+        NetDev meta;
+
+        int id;
+
+        LIST_HEAD(UfdLink, links);
+        Hashmap *ufd_links_by_section;
+};
+
+void ufd_link_free(UfdLink *ufd_link);
+void ufd_groups_clear(void);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(UfdLink*, ufd_link_free);
+#define _cleanup_ufdlink_free_ _cleanup_(ufd_link_freep)
+
+extern const NetDevVTable ufd_group_vtable;
+
+const char *ufd_type_to_string(UfdType d) _const_;
+UfdType ufd_type_from_string(const char *d) _pure_;
+
+int config_parse_ufd_link_name(const char *unit,
+                               const char *filename,
+                               unsigned line,
+                               const char *section,
+                               unsigned section_line,
+                               const char *lvalue,
+                               int ltype,
+                               const char *rvalue,
+                               void *data,
+                               void *userdata);
+
+int config_parse_ufd_link_type(const char *unit,
+                               const char *filename,
+                               unsigned line,
+                               const char *section,
+                               unsigned section_line,
+                               const char *lvalue,
+                               int ltype,
+                               const char *rvalue,
+                               void *data,
+                               void *userdata);
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 8119205..698331c 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -49,6 +49,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_TUN] = &tun_vtable,
         [NETDEV_KIND_TAP] = &tap_vtable,
         [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
+        [NETDEV_KIND_UFDGROUP] = &ufd_group_vtable,
 };
 
 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
@@ -70,6 +71,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_TUN] = "tun",
         [NETDEV_KIND_TAP] = "tap",
         [NETDEV_KIND_IP6TNL] = "ip6tnl",
+        [NETDEV_KIND_UFDGROUP] = "ufd",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
@@ -592,6 +594,29 @@ static int netdev_create(NetDev *netdev, Link *link,
         return 0;
 }
 
+void netdev_clear_groups(void) {
+        /* for now only Uplink failure detection groups are defined. */
+        return ufd_groups_clear();
+}
+
+int netdev_create_group(NetDev *netdev) {
+        int r;
+        assert(netdev);
+
+        switch (NETDEV_VTABLE(netdev)->create_type) {
+        case NETDEV_CREATE_GROUP:
+                r = NETDEV_VTABLE(netdev)->create(netdev);
+                if (r < 0)
+                        return r;
+                break;
+        default:
+                assert_not_reached("Can not create group netdev");
+
+        }
+
+        return 0;
+}
+
 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
         int r;
@@ -733,6 +758,17 @@ static int netdev_load_one(Manager *manager, const char *filename) {
                         return 0;
 
                 break;
+
+        case NETDEV_CREATE_GROUP:
+                r = hashmap_put(manager->group_netdevs, netdev->ifname, netdev);
+                if (r < 0) {
+                        log_error("Can not add Group '%s' to manager: %s",
+                                   netdev->ifname, strerror(-r));
+                        return 0;
+                }
+
+                break;
+
         default:
                 break;
         }
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index 3756b1e..3674b59 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -57,6 +57,7 @@ typedef enum NetDevKind {
         NETDEV_KIND_DUMMY,
         NETDEV_KIND_TUN,
         NETDEV_KIND_TAP,
+        NETDEV_KIND_UFDGROUP,
         _NETDEV_KIND_MAX,
         _NETDEV_KIND_INVALID = -1
 } NetDevKind;
@@ -74,6 +75,7 @@ typedef enum NetDevCreateType {
         NETDEV_CREATE_INDEPENDENT,
         NETDEV_CREATE_MASTER,
         NETDEV_CREATE_STACKED,
+        NETDEV_CREATE_GROUP,
         _NETDEV_CREATE_MAX,
         _NETDEV_CREATE_INVALID = -1,
 } NetDevCreateType;
@@ -111,6 +113,7 @@ struct NetDev {
 #include "networkd-netdev-tunnel.h"
 #include "networkd-netdev-dummy.h"
 #include "networkd-netdev-tuntap.h"
+#include "networkd-netdev-ufd-group.h"
 
 struct NetDevVTable {
         /* How much memory does an object of this unit type need */
@@ -177,6 +180,7 @@ DEFINE_CAST(VETH, Veth);
 DEFINE_CAST(DUMMY, Dummy);
 DEFINE_CAST(TUN, TunTap);
 DEFINE_CAST(TAP, TunTap);
+DEFINE_CAST(UFDGROUP, UfdGroup);
 
 int netdev_load(Manager *manager);
 void netdev_drop(NetDev *netdev);
@@ -192,6 +196,8 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *newlink);
 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback);
 int netdev_get_mac(const char *ifname, struct ether_addr **ret);
 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t cb);
+int netdev_create_group(NetDev *netdev);
+void netdev_clear_groups(void);
 
 const char *netdev_kind_to_string(NetDevKind d) _const_;
 NetDevKind netdev_kind_from_string(const char *d) _pure_;
diff --git a/src/network/networkd-ufd-daemon.c b/src/network/networkd-ufd-daemon.c
new file mode 100644
index 0000000..106465f
--- /dev/null
+++ b/src/network/networkd-ufd-daemon.c
@@ -0,0 +1,1321 @@
+
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+    This file is part of systemd.
+
+    Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+    systemd is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    systemd is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <pthread.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <linux/genetlink.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <net/if.h>
+
+#include "sd-network.h"
+#include "sd-rtnl.h"
+#include "rtnl-util.h"
+#include "util.h"
+#include "ctype.h"
+#include "socket-util.h"
+#include "strv.h"
+#include "networkd-ufd-daemon.h"
+
+#define UFD_UPLINK                   0x01
+#define UFD_DOWNLINK                 0x02
+
+#define UFD_RCV_PORT_EVENT           0x00
+#define UFD_IGNORE_PORT_DOWN_EVENT   0x01
+#define UFD_IGNORE_PORT_UP_EVENT     0x02
+
+typedef struct UfdDaemon UfdDaemon;
+typedef struct UfddPortInfo UfddPortInfo;
+typedef struct UfddGroup UfddGroup;
+typedef struct UfddPort UfddPort;
+
+typedef enum PortState {
+        UFD_PORT_ADMIN_UP = 1,
+        UFD_PORT_ADMIN_DOWN,
+        UFD_PORT_OPER_UP,
+        UFD_PORT_OPER_DOWN,
+        _UFD_PORT_STATE_MAX,
+        _UFD_PORT_STATE_INVALID = -1
+} PortState;
+
+/* struct to hold uplink and downlink info */
+struct UfddPort {
+        unsigned int if_index;
+        unsigned char link_type;
+        unsigned char rcv_port_event;
+        PortState admin_state;
+        PortState ufd_state;
+        UfddPort *next_port;
+};
+
+/* struct to hold group info */
+struct UfddGroup {
+        char *state_file;
+        char *config_file;
+        unsigned int grp_id;
+        unsigned int act_uplink_count;
+        UfddPort *up_link_ports;
+        UfddPort *down_link_ports;
+        UfddGroup *next_group;
+};
+
+/* struct to hold port info */
+struct UfddPortInfo {
+        unsigned int if_idx;
+        UfddGroup *grp_info;
+        UfddPort *if_idx_info;
+        UfddPortInfo *next_if_idx;
+};
+
+struct UfdDaemon {
+        char *state_file;
+        sd_rtnl *rtnl;
+        sd_event *event;
+        UfddPortInfo *port_info;
+        UfddGroup *group_info;
+};
+
+/* Global UFD structure. */
+static UfdDaemon g_ufdd;
+
+static int ufd_port_get_state(int ifindex,
+                              PortState *admin_state,
+                              PortState *oper_state) {
+        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+        sd_rtnl *rtnl = g_ufdd.rtnl;
+        sd_rtnl_message *link;
+        int r;
+
+        assert(admin_state);
+        assert(oper_state);
+        assert(rtnl);
+
+        r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_message_request_dump(req, true);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_call(rtnl, req, 0, &reply);
+        if (r < 0)
+                return r;
+
+        for (link = reply; link; link = sd_rtnl_message_next(link)) {
+                int link_ifindex;
+
+                r = sd_rtnl_message_link_get_ifindex(link, &link_ifindex);
+                if (r < 0 || ifindex <= 0) {
+                        log_warning("UFD rtnl: received link message without valid ifindex");
+                        continue;
+                }
+
+                if (link_ifindex == ifindex) {
+                        unsigned int flags;
+                        r = sd_rtnl_message_link_get_flags(link, &flags);
+                        if (r < 0) {
+                                log_error("UFD: Could not get link flags");
+                                return r;
+                        }
+
+                        if ((flags & IFF_UP) == IFF_UP)
+                                *admin_state = UFD_PORT_ADMIN_UP;
+                        else
+                                *admin_state = UFD_PORT_ADMIN_DOWN;
+
+                        if ((flags & IFF_RUNNING) == IFF_RUNNING)
+                                *oper_state = UFD_PORT_OPER_UP;
+                        else
+                                *oper_state = UFD_PORT_OPER_DOWN;
+
+                        break;
+                }
+        }
+
+        return 0;
+}
+
+static int port_set_handler(sd_rtnl *rtnl,
+                            sd_rtnl_message *m,
+                            void *userdata) {
+        int r;
+
+        r = sd_rtnl_message_get_errno(m);
+        if (r < 0)
+                log_error("UFD: Failed to set port state, error: %s", strerror(-r));
+
+        return 1;
+}
+
+static int ufd_port_set_flags(unsigned int ifindex,
+                              unsigned flags) {
+        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+        sd_rtnl *rtnl = g_ufdd.rtnl;
+        int r;
+
+        assert(rtnl);
+
+        r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, ifindex);
+        if (r < 0) {
+                log_error("UFD: Could not allocate RTM_SETLINK message: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_message_link_set_flags(req, flags, IFF_UP);
+        if (r < 0) {
+                log_error("UFD: Could not set link flags: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_call_async(rtnl, req, port_set_handler, NULL, 0, NULL);
+        if (r < 0) {
+                log_error("UFD: Could not send rtnetlink message: %s", strerror(-r));
+                return r;
+        }
+
+        return 0;
+}
+
+static int ufd_port_info_add(unsigned int port_id,
+                             UfddGroup *grp_ptr,
+                             UfddPort *ufd_port_ptr) {
+        UfddPortInfo *port_info_ptr = NULL;
+        UfddPortInfo *cur_ptr = NULL;
+
+        assert(grp_ptr);
+        assert(ufd_port_ptr);
+
+        port_info_ptr = (UfddPortInfo *)calloc(1, sizeof(UfddPortInfo));
+        if (!port_info_ptr)
+                return -ENOMEM;
+
+        port_info_ptr->if_idx = port_id;
+        port_info_ptr->grp_info = grp_ptr;
+        port_info_ptr->if_idx_info = ufd_port_ptr;
+        port_info_ptr->next_if_idx = NULL;
+
+        /* Add port info into g_ufdd.port_info database */
+        if (!g_ufdd.port_info) {
+                g_ufdd.port_info = port_info_ptr;
+        } else {
+                cur_ptr = g_ufdd.port_info;
+
+                while (cur_ptr->next_if_idx)
+                        cur_ptr = cur_ptr->next_if_idx;
+
+                cur_ptr->next_if_idx = port_info_ptr;
+        }
+
+        return 0;
+}
+
+/* To check if the new ports are already present in ufd_port_info database */
+static bool is_port_present(unsigned int *port_list,
+                            unsigned int port_count,
+                            unsigned int *group_id,
+                            unsigned int *port_id) {
+        UfddPortInfo *cur_ptr = g_ufdd.port_info;
+        unsigned int *port_ptr = port_list;
+        unsigned int i = 0;
+
+        assert(group_id);
+        assert(port_id);
+
+        if (!port_list || 0 == port_count)
+                return false;
+
+        if (!cur_ptr)
+                return false;
+
+        /* Check if any of the new ports is present in g_ufdd.port_info */
+        for (i = 0; i < port_count; i++) {
+                while (cur_ptr) {
+                        if (cur_ptr->if_idx == *port_ptr) {
+                                *group_id = cur_ptr->grp_info->grp_id;
+                                *port_id = cur_ptr->if_idx;
+
+                                return true;
+                        }
+
+                        cur_ptr = cur_ptr->next_if_idx;
+                }
+
+                cur_ptr = g_ufdd.port_info;
+                port_ptr++;
+       }
+
+       return false;
+}
+
+/* Get group structure from g_ufdd.group_info DB */
+static UfddGroup *get_group(unsigned int group_id) {
+        UfddGroup *cur_ptr = g_ufdd.group_info;
+
+        while (cur_ptr) {
+                if (cur_ptr->grp_id == group_id)
+                        return cur_ptr;
+
+                cur_ptr = cur_ptr->next_group;
+        }
+
+        return NULL;
+}
+
+/* Add Ports list to the Group */
+static int ufd_group_ports_add(UfddGroup *grp_ptr,
+                               unsigned char link_type,
+                               unsigned int *port_list,
+                               unsigned int port_count) {
+        UfddPort *port_ptr = NULL;
+        UfddPort *ufd_port_ptr = NULL;
+        unsigned int act_up_port = 0;
+        unsigned int *port_to_add = port_list;
+        unsigned int i;
+        int r;
+
+        assert(grp_ptr);
+
+        if (!port_to_add || 0 == port_count) {
+                log_debug("UFD: No ports found to add in the group:%d", grp_ptr->grp_id);
+                return 0;
+        }
+
+        if (UFD_UPLINK == link_type) {
+                ufd_port_ptr = grp_ptr->up_link_ports;
+                act_up_port = grp_ptr->act_uplink_count;
+        } else if (UFD_DOWNLINK == link_type) {
+                ufd_port_ptr = grp_ptr->down_link_ports;
+        } else {
+                log_error("UFD: Unknown link_type:%d", link_type);
+                return -EINVAL;
+        }
+
+        /* Move the ptr to end of post list */
+        if (ufd_port_ptr) {
+                while (ufd_port_ptr->next_port)
+                        ufd_port_ptr = ufd_port_ptr->next_port;
+        }
+
+        /* Add ports to the port list of the group */
+        for (i = 0; i < port_count; i++) {
+                port_ptr = (UfddPort *)calloc(1, sizeof(UfddPort));
+                if (!port_ptr)
+                        return -ENOMEM;
+
+                port_ptr->if_index = *port_to_add;
+
+                r = ufd_port_get_state(port_ptr->if_index, &port_ptr->admin_state, &port_ptr->ufd_state);
+                if (r < 0) {
+                        free(port_ptr);
+                        return r;
+                }
+
+                port_ptr->rcv_port_event = UFD_RCV_PORT_EVENT;
+                port_ptr->link_type = link_type;
+                port_ptr->next_port = NULL;
+
+                if ((UFD_UPLINK == link_type) && (UFD_PORT_ADMIN_UP == port_ptr->admin_state) &&
+                    (UFD_PORT_OPER_UP == port_ptr->ufd_state))
+                        act_up_port++;
+
+                if (ufd_port_ptr) {
+                        ufd_port_ptr->next_port = port_ptr;
+                        ufd_port_ptr = ufd_port_ptr->next_port;
+                } else {
+                        ufd_port_ptr = port_ptr;
+                        if (UFD_UPLINK == link_type)
+                                grp_ptr->up_link_ports = port_ptr;
+                        else
+                                grp_ptr->down_link_ports = port_ptr;
+                }
+
+                r = ufd_port_info_add(*port_to_add, grp_ptr, port_ptr);
+                if (r < 0)
+                        return r;
+
+                port_to_add++;
+        }
+
+        if (UFD_UPLINK == port_ptr->link_type) {
+                grp_ptr->act_uplink_count = act_up_port;
+                log_debug("UFD: Active uplink port count:%d for group:%d", grp_ptr->act_uplink_count, grp_ptr->grp_id);
+        }
+
+        return 0;
+}
+
+/* Update downlink ports based on uplink events */
+static int update_downlink_ports(UfddPort *port_ptr,
+                                 PortState port_state) {
+        unsigned flags = 0;
+        int r;
+
+        while (port_ptr) {
+                if ((port_ptr->admin_state == UFD_PORT_ADMIN_UP) &&
+                    (port_ptr->ufd_state != port_state)) {
+
+                        if (port_state == UFD_PORT_OPER_UP) {
+                                port_ptr->ufd_state = UFD_PORT_OPER_UP;
+                                port_ptr->rcv_port_event = UFD_IGNORE_PORT_UP_EVENT;
+                                flags = IFF_UP | IFF_RUNNING;
+                        } else {
+                                port_ptr->ufd_state = UFD_PORT_OPER_DOWN;
+                                port_ptr->rcv_port_event = UFD_IGNORE_PORT_DOWN_EVENT;
+                                flags &= (unsigned int)~IFF_UP;
+                        }
+
+                        r = ufd_port_set_flags(port_ptr->if_index, flags);
+                        if (r < 0)
+                                return r;
+                }
+
+                port_ptr = port_ptr->next_port;
+        }
+
+        return 0;
+}
+
+/* Delete port info from g_ufdd.port_info DB */
+static void ufd_port_info_del(unsigned int port_id) {
+        UfddPortInfo *prev_port_ptr = NULL;
+        UfddPortInfo *cur_port_ptr = g_ufdd.port_info;
+
+        while (cur_port_ptr) {
+                if (cur_port_ptr->if_idx == port_id) {
+
+                        if (cur_port_ptr == g_ufdd.port_info) {
+                                g_ufdd.port_info = cur_port_ptr->next_if_idx;
+                        } else {
+                                prev_port_ptr->next_if_idx = cur_port_ptr->next_if_idx;
+                        }
+
+                        free(cur_port_ptr);
+                        cur_port_ptr = NULL;
+
+                        break;
+                }
+
+                prev_port_ptr = cur_port_ptr;
+                cur_port_ptr = cur_port_ptr->next_if_idx;
+        }
+}
+
+/* Delete port from the groupDB */
+static unsigned int ufd_group_port_del(UfddGroup *group_ptr,
+                                       char link_type,
+                                       unsigned int port_id) {
+        UfddPort *prev_port_ptr = NULL;
+        UfddPort *cur_port_ptr = NULL;
+        unsigned int act_uplink_port = 0;
+
+        assert(group_ptr);
+
+        cur_port_ptr = (link_type == UFD_UPLINK) ? group_ptr->up_link_ports : group_ptr->down_link_ports;
+        prev_port_ptr = cur_port_ptr;
+
+        while (cur_port_ptr) {
+                if (cur_port_ptr->if_index == port_id) {
+
+                        if (cur_port_ptr == prev_port_ptr) {
+                                if (UFD_UPLINK == link_type)
+                                        group_ptr->up_link_ports = cur_port_ptr->next_port;
+                                else
+                                        group_ptr->down_link_ports = cur_port_ptr->next_port;
+                        } else {
+                                prev_port_ptr->next_port = cur_port_ptr->next_port;
+                        }
+
+                        if ((UFD_PORT_OPER_UP == cur_port_ptr->ufd_state) && (UFD_UPLINK == cur_port_ptr->link_type))
+                                act_uplink_port = 1;
+
+                        log_debug("UFD: Deleted port:%d ufd_state:%d link_state:%d, uplink_port:%d",
+                                  port_id, cur_port_ptr->ufd_state, cur_port_ptr->link_type, act_uplink_port);
+
+                        free(cur_port_ptr);
+                        cur_port_ptr = NULL;
+
+                        /* delete port information from port_info db */
+                        ufd_port_info_del(port_id);
+
+                        return act_uplink_port;
+                }
+
+                prev_port_ptr = cur_port_ptr;
+                cur_port_ptr = cur_port_ptr->next_port;
+        }
+
+        return act_uplink_port;
+}
+
+/* Delete port list from GroupDB */
+static unsigned int ufd_group_port_list_del(UfddGroup *group_ptr,
+                                            char link_type,
+                                            unsigned int *port_list,
+                                            unsigned int port_count) {
+        unsigned int act_port_count = 0;
+        unsigned int i = 0;
+        unsigned int *port_to_del = port_list;
+
+        assert(group_ptr);
+
+        for (i = 0; i < port_count; i++) {
+                unsigned int count = 0;
+
+                count = ufd_group_port_del(group_ptr, link_type, *port_to_del);
+
+                act_port_count += count;
+
+                port_to_del++;
+        }
+
+        return act_port_count;
+}
+
+/* Check if all the ports to be deleted are present in group */
+static bool ufd_group_port_check(UfddPort *port_ptr,
+                                 unsigned int *port_list,
+                                 unsigned int port_count) {
+        unsigned int port_found_cnt = 0;
+        unsigned int *port_to_check = port_list;
+        unsigned int i;
+
+        for (i = 0; i < port_count; i++) {
+                UfddPort *cur_port_ptr = port_ptr;
+
+                while (cur_port_ptr) {
+                        if (cur_port_ptr->if_index == *port_to_check) {
+                                port_found_cnt++;
+                                break;
+                        }
+
+                        cur_port_ptr = cur_port_ptr->next_port;
+                }
+
+                port_to_check++;
+        }
+
+        if (port_found_cnt != port_count)
+                return false;
+        else
+                return true;
+}
+
+/* Delete complete portlist of the group */
+static void ufd_group_all_port_del(UfddGroup *group_ptr,
+                                   char link_type) {
+        UfddPort *prev_port_ptr = NULL;
+        UfddPort *cur_port_ptr = NULL;
+
+        if (UFD_UPLINK == link_type) {
+                cur_port_ptr = group_ptr->up_link_ports;
+                group_ptr->up_link_ports = NULL;
+        } else {
+                cur_port_ptr = group_ptr->down_link_ports;
+                group_ptr->down_link_ports = NULL;
+        }
+
+        while (cur_port_ptr) {
+                prev_port_ptr = cur_port_ptr;
+                cur_port_ptr = cur_port_ptr->next_port;
+
+                ufd_port_info_del(prev_port_ptr->if_index);
+
+                free(prev_port_ptr);
+                prev_port_ptr = NULL;
+        }
+}
+
+/* Delete group */
+static int ufd_group_del(unsigned int group_id,
+                         unsigned int *uplink_ports,
+                         unsigned int uplink_count,
+                         unsigned int *downlink_ports,
+                         unsigned int downlink_count) {
+        UfddGroup *group_ptr = NULL;
+        UfddGroup *cur_grp_ptr = NULL;
+        UfddGroup *prev_grp_ptr = NULL;
+        UfddPort *cur_port_ptr = NULL;
+        unsigned int act_port_count = 0;
+        int r;
+
+        group_ptr = get_group(group_id);
+        if (!group_ptr)
+                return -EINVAL;
+
+        /* If uplink_count and downlink_count are zero, delete all uplink and downlink ports */
+        if ((0 == uplink_count) && (0 == downlink_count)) {
+                log_debug("UFD: Deleting uplink & downlink ports for group:%d", group_id);
+
+                ufd_group_all_port_del(group_ptr, UFD_UPLINK);
+                ufd_group_all_port_del(group_ptr, UFD_DOWNLINK);
+
+                /* if pointer to up_link_ports and down_link_ports are NULL in the group, delete group */
+                if ((!group_ptr->up_link_ports) && (!group_ptr->down_link_ports)) {
+                        cur_grp_ptr = g_ufdd.group_info;
+
+                        while (cur_grp_ptr) {
+                                if (cur_grp_ptr->grp_id == group_id) {
+
+                                        if (cur_grp_ptr == g_ufdd.group_info)
+                                                g_ufdd.group_info = cur_grp_ptr->next_group;
+                                        else
+                                                prev_grp_ptr->next_group = cur_grp_ptr->next_group;
+
+                                        unlink(cur_grp_ptr->state_file);
+                                        free(cur_grp_ptr->state_file);
+                                        free(cur_grp_ptr->config_file);
+
+                                        free(cur_grp_ptr);
+                                        cur_grp_ptr = NULL;
+
+                                        log_debug("UFD: Group: %d deleted", group_id);
+
+                                        return 0;
+                                }
+
+                                prev_grp_ptr = cur_grp_ptr;
+                                cur_grp_ptr = cur_grp_ptr->next_group;
+                        }
+
+                } else {
+                        log_debug("UFD: failed to delete group: %d", group_id);
+                        return -EINVAL;
+                }
+        }
+
+        /* delete uplink ports */
+        if (uplink_count != 0) {
+                if (false == ufd_group_port_check(group_ptr->up_link_ports, uplink_ports, uplink_count)) {
+                        log_error("UFD: Invalid uplink ports list group:%d", group_id);
+                        return -EINVAL;
+                }
+
+                act_port_count = ufd_group_port_list_del(group_ptr, UFD_UPLINK, uplink_ports, uplink_count);
+                group_ptr->act_uplink_count = group_ptr->act_uplink_count - act_port_count;
+
+                log_debug("UFD: Active uplink ports number for group:%d is %d", group_id, group_ptr->act_uplink_count);
+        }
+
+        /* delete downlink ports */
+        if (downlink_count != 0) {
+                if (false == ufd_group_port_check(group_ptr->down_link_ports, downlink_ports, downlink_count)) {
+                        log_error("UFD: Invalid uplink ports list group:%d", group_id);
+                        return -EINVAL;
+                }
+
+                ufd_group_port_list_del(group_ptr, UFD_DOWNLINK, downlink_ports, downlink_count);
+        }
+
+        /* down downlink port states if no active/up Uplink ports */
+        if (0 == group_ptr->act_uplink_count) {
+                cur_port_ptr = group_ptr->down_link_ports;
+
+                while (cur_port_ptr) {
+                        if (cur_port_ptr->ufd_state != UFD_PORT_OPER_DOWN) {
+                                r = update_downlink_ports(cur_port_ptr, UFD_PORT_OPER_DOWN);
+                                if (r < 0) {
+                                        log_error("UFD: Could not update downlink ports state, error: %s", strerror(-r));
+                                        return r;
+                                }
+                        }
+
+                        cur_port_ptr = cur_port_ptr->next_port;
+                }
+        }
+
+        return 0;
+}
+
+static int verify_ports(unsigned int *uplink_ports,
+                        unsigned int uplink_count,
+                        unsigned int *downlink_ports,
+                        unsigned int downlink_count) {
+        unsigned int group_nr = 0;
+        unsigned int port_id = 0;
+        unsigned int i;
+        unsigned int j;
+
+        if (true == is_port_present(uplink_ports, uplink_count, &group_nr, &port_id)) {
+                log_error("UFD: Uplink Port:%d is already mapped to a group:%d", port_id, group_nr);
+                return -EEXIST;
+        }
+
+        group_nr = 0;
+        port_id = 0;
+
+        if (true == is_port_present(downlink_ports, downlink_count, &group_nr, &port_id)) {
+                log_error("UFD: Downlink Port:%d is already mapped to a group:%d", port_id, group_nr);
+                return -EEXIST;
+        }
+
+        for (i = 0; i < uplink_count; i++)
+                for (j = 0; j < downlink_count; j++)
+                        if (uplink_ports[i] == downlink_ports[j]) {
+                                log_error("UFD: Uplink port %d found in the downlink port list", uplink_ports[i]);
+                                return -EEXIST;
+                        }
+
+        return 0;
+}
+
+/* Add group to the group DB */
+static int ufd_group_add(unsigned int group_id,
+                         unsigned int *uplink_ports,
+                         unsigned int uplink_count,
+                         unsigned int *downlink_ports,
+                         unsigned int downlink_count) {
+        UfddGroup *group_ptr = NULL;
+        UfddGroup *cur_ptr = NULL;
+        UfddPort *cur_port_ptr = NULL;
+        int r;
+        bool add_new_group = false;
+
+        cur_ptr = g_ufdd.group_info;
+
+        r = verify_ports(uplink_ports, uplink_count, downlink_ports, downlink_count);
+        if (r < 0)
+                return r;
+
+        /* Check if group is already present */
+        group_ptr = get_group(group_id);
+
+        if (!group_ptr) {
+                /*if not present create*/
+                group_ptr = (UfddGroup *)calloc(1, sizeof(UfddGroup));
+
+                if (!group_ptr)
+                        return -ENOMEM;
+
+                group_ptr->grp_id = group_id;
+                group_ptr->act_uplink_count = 0;
+                group_ptr->up_link_ports = NULL;
+                group_ptr->down_link_ports = NULL;
+                group_ptr->next_group = NULL;
+
+                add_new_group = true;
+        }
+
+        /* Add uplink ports to the group */
+        r = ufd_group_ports_add(group_ptr, UFD_UPLINK, uplink_ports, uplink_count);
+        if (r < 0) {
+                int del_err;
+                log_error("UFD: Uplink Port addition to group:%d failed error: %s", group_id, strerror(-r));
+
+                del_err = ufd_group_del(group_id, uplink_ports, uplink_count, NULL, 0);
+                if (del_err < 0)
+                        log_error("UFD: Uplink Port deletion failed. Error: %s", strerror(-del_err));
+
+                return r;
+        }
+
+        /* Add downlink ports to the group */
+        r = ufd_group_ports_add(group_ptr, UFD_DOWNLINK, downlink_ports, downlink_count);
+        if (r < 0) {
+                int del_err;
+                log_error("UFD: Downlink Port addition to group:%d failed error: %s", group_id, strerror(-r));
+
+                del_err = ufd_group_del(group_id, NULL, 0, downlink_ports, downlink_count);
+                if (del_err < 0)
+                        log_error("UFD: Downlink Port deletion failed. Error: %s", strerror(-del_err));
+
+                return r;
+        }
+
+        /* Add group to group_info DB if new group */
+        if (add_new_group) {
+                if (!g_ufdd.group_info) {
+                        g_ufdd.group_info = group_ptr;
+                } else {
+                        while (cur_ptr->next_group)
+                                cur_ptr = cur_ptr->next_group;
+
+                        cur_ptr->next_group = group_ptr;
+                }
+
+                log_debug("UFD: Added UFD Group:%d to UFD database", group_id);
+        }
+
+        /* down downlink port states if no active/up Uplink ports */
+        if (group_ptr->act_uplink_count == 0) {
+                cur_port_ptr = group_ptr->down_link_ports;
+
+                while (cur_port_ptr) {
+                        if (cur_port_ptr->ufd_state != UFD_PORT_OPER_DOWN) {
+                                r = update_downlink_ports(cur_port_ptr, UFD_PORT_OPER_DOWN);
+                                if (r < 0) {
+                                        log_error("UFD: Could not update downlink ports state, error: %s", strerror(-r));
+                                        return r;
+                                }
+                        }
+
+                        cur_port_ptr = cur_port_ptr->next_port;
+                }
+        }
+
+        return 0;
+}
+
+/* Update UFD DB based on the port event received */
+static int ufd_update_port_event(unsigned int port,
+                                 char port_event) {
+        UfddPortInfo *cur_port_info_ptr = NULL;
+        UfddGroup *group_ptr = NULL;
+        UfddPort *port_ptr = NULL;
+        bool is_port_found = false;
+        int r;
+
+        cur_port_info_ptr = g_ufdd.port_info;
+
+        while (cur_port_info_ptr) {
+
+                if (cur_port_info_ptr->if_idx == port) {
+                        group_ptr = cur_port_info_ptr->grp_info;
+                        port_ptr = cur_port_info_ptr->if_idx_info;
+                        is_port_found = true;
+                        break;
+                }
+
+                cur_port_info_ptr = cur_port_info_ptr->next_if_idx;
+        }
+
+        if (!is_port_found) {
+                log_error("UFD: Port:%d not found", port);
+                return -EINVAL;
+        }
+
+        if (!group_ptr) {
+                log_error("UFD: Group not found for port:%d", port);
+                return -EINVAL;
+        }
+
+        if (!port_ptr) {
+                log_error("UFD: Port info not found for port:%d", port);
+                return -EINVAL;
+        }
+
+        switch (port_event) {
+        case UFD_PORT_OPER_DOWN:
+
+                if (UFD_RCV_PORT_EVENT == port_ptr->rcv_port_event) {
+                        port_ptr->admin_state = UFD_PORT_ADMIN_UP;
+                } else {
+                        port_ptr->rcv_port_event--;
+                        break;
+                }
+
+                if (UFD_PORT_OPER_UP == port_ptr->ufd_state) {
+                        port_ptr->ufd_state = UFD_PORT_OPER_DOWN;
+
+                        if (UFD_UPLINK == port_ptr->link_type) {
+
+                                group_ptr->act_uplink_count--;
+                                log_debug("UFD: Uplink count decremented: %d", group_ptr->act_uplink_count);
+
+                                if (0 == group_ptr->act_uplink_count) {
+                                        r = update_downlink_ports(group_ptr->down_link_ports, UFD_PORT_OPER_DOWN);
+                                        if (r < 0) {
+                                                log_error("UFD: Could not update downlink ports state, error: %s",
+                                                          strerror(-r));
+                                                return r;
+                                        }
+                                }
+                        }
+                }
+
+                break;
+
+        case UFD_PORT_OPER_UP:
+
+                if (port_ptr->rcv_port_event != UFD_RCV_PORT_EVENT) {
+                        port_ptr->rcv_port_event--;
+                        break;
+                }
+
+                if (port_ptr->admin_state != UFD_PORT_ADMIN_UP)
+                        break;
+
+                port_ptr->ufd_state = UFD_PORT_OPER_UP;
+
+                if (UFD_UPLINK == port_ptr->link_type) {
+                        group_ptr->act_uplink_count++;
+                        log_debug("UFD: Uplink count incremented: %d", group_ptr->act_uplink_count);
+
+                        if (1 == group_ptr->act_uplink_count) {
+                                r = update_downlink_ports(group_ptr->down_link_ports, UFD_PORT_OPER_UP);
+                                if (r < 0) {
+                                        log_error("UFD: Could not update downlink ports state, error: %s",
+                                                  strerror(-r));
+                                        return r;
+                                }
+                        }
+                }
+
+                break;
+
+        case UFD_PORT_ADMIN_DOWN:
+
+                if (UFD_RCV_PORT_EVENT == port_ptr->rcv_port_event) {
+                        port_ptr->admin_state = UFD_PORT_ADMIN_DOWN;
+                } else {
+                        port_ptr->rcv_port_event--;
+                        break;
+                }
+
+                port_ptr->ufd_state = UFD_PORT_OPER_DOWN;
+
+                if (UFD_UPLINK == port_ptr->link_type) {
+                        group_ptr->act_uplink_count--;
+                        log_debug("UFD: Uplink count decremented: %d", group_ptr->act_uplink_count);
+
+                        if (0 == group_ptr->act_uplink_count) {
+                                r = update_downlink_ports(group_ptr->down_link_ports, UFD_PORT_OPER_DOWN);
+                                if (r < 0) {
+                                        log_error("UFD: Could not update downlink ports state, error: %s",
+                                                  strerror(-r));
+                                        return r;
+                                }
+                        }
+                }
+
+                break;
+
+        default:
+                log_error("UFD: Unknown port Event:%d received on port:%d", port_event, port);
+                return -EINVAL;
+
+        }
+
+        return 0;
+}
+
+/* Cleanup for UFD db */
+static void ufd_db_cleanup(void) {
+        UfddGroup *cur_grp_ptr = NULL;
+        UfddGroup *tmp_grp_ptr = NULL;
+        UfddPortInfo *cur_port_ptr = NULL;
+        UfddPortInfo *temp_port_ptr = NULL;
+
+        log_debug("UFD: Free database");
+
+        cur_grp_ptr = g_ufdd.group_info;
+
+        /* cleanup of group_info DB */
+        while (cur_grp_ptr) {
+                ufd_group_all_port_del(cur_grp_ptr, UFD_UPLINK);
+                ufd_group_all_port_del(cur_grp_ptr, UFD_DOWNLINK);
+
+                tmp_grp_ptr = cur_grp_ptr;
+                cur_grp_ptr = cur_grp_ptr->next_group;
+
+                unlink(tmp_grp_ptr->state_file);
+                free(tmp_grp_ptr->state_file);
+                free(tmp_grp_ptr->config_file);
+
+                free(tmp_grp_ptr);
+                tmp_grp_ptr = NULL;
+        }
+
+        cur_port_ptr = g_ufdd.port_info;
+
+        /* Cleanup of port_info DB */
+        while (cur_port_ptr) {
+                temp_port_ptr = cur_port_ptr;
+                cur_port_ptr = cur_port_ptr->next_if_idx;
+
+                free(temp_port_ptr);
+                temp_port_ptr = NULL;
+        }
+}
+
+static int ufd_rtnl_event(sd_rtnl *rtnl,
+                          sd_rtnl_message *message,
+                          void *userdata) {
+        unsigned int flags;
+        char state;
+        int r;
+        int ifindex;
+
+        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
+        if (r < 0 || ifindex <= 0) {
+                log_warning("UFD rtnl: received link message without valid ifindex");
+                return 0;
+        }
+
+        r = sd_rtnl_message_link_get_flags(message, &flags);
+        if (r < 0) {
+                log_warning("UFD: Could not get link flags");
+                return r;
+        }
+
+        if ((flags & IFF_UP) == IFF_UP) {
+                if ((flags & IFF_RUNNING) == IFF_RUNNING)
+                        state = UFD_PORT_OPER_UP;
+                else
+                        state = UFD_PORT_OPER_DOWN;
+        } else {
+                state = UFD_PORT_ADMIN_DOWN;
+        }
+
+        r = ufd_update_port_event(ifindex, state);
+        if (r < 0) {
+                log_error("UFD: Could not update port event");
+                return 0;
+        }
+
+        return 1;
+}
+
+static int monitoring_init(UfdDaemon *ufdd) {
+        int r;
+
+        assert(ufdd);
+
+        r = sd_rtnl_open(&ufdd->rtnl, 1, RTNLGRP_LINK);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_attach_event(ufdd->rtnl, ufdd->event, 0);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_add_match(ufdd->rtnl, RTM_NEWLINK, ufd_rtnl_event, NULL);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_add_match(ufdd->rtnl, RTM_DELLINK, ufd_rtnl_event, NULL);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int parse_ports_list(char *port_list,
+                            uint32_t **out_port_list,
+                            uint32_t *port_num) {
+        char *temp_list = NULL;
+        char *token = NULL;
+        uint32_t port_count = 0;
+        uint32_t *port_ptr = NULL;
+        uint32_t ifindex;
+        uint32_t i = 0;
+
+        assert(port_list);
+
+        temp_list = (char *) malloc(strlen(port_list) + 1);
+        if (!temp_list)
+                return -ENOMEM;
+
+        strncpy(temp_list, port_list, strlen(port_list) + 1);
+
+        /* check for validity of the port_list first */
+        token = strtok(port_list, ",");
+        while (token) {
+                ifindex = if_nametoindex(token);
+
+                if (0 == ifindex) {
+                        log_error("UFD got invalid portname = %s", token);
+                        free(temp_list);
+                        return -EINVAL;
+                }
+
+                port_count++;
+                token = strtok(NULL, ",");
+        }
+
+        port_ptr = (uint32_t *)malloc(port_count * sizeof(uint32_t));
+        if (!port_ptr) {
+                free(temp_list);
+                return -ENOMEM;
+        }
+
+        token = strtok(temp_list, ",");
+        while (token) {
+                ifindex = if_nametoindex(token);
+                *(port_ptr+i) = ifindex;
+                token = strtok(NULL, ",");
+                i++;
+        }
+
+        *out_port_list = port_ptr;
+        *port_num = port_count;
+
+        free(temp_list);
+
+        return 0;
+}
+
+static int ufd_daemon_save(void) {
+        _cleanup_free_ char *temp_path = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *group_list = NULL;
+        UfddGroup *ufd_group;
+        bool space;
+        int r;
+
+        assert(g_ufdd.state_file);
+
+        r = fopen_temporary(g_ufdd.state_file, &f, &temp_path);
+        if (r < 0)
+                return r;
+
+        fchmod(fileno(f), 0644);
+
+        fprintf(f, "# This is private data. Do not parse.\n");
+
+        fputs("GROUP_LIST=", f);
+        space = false;
+
+        ufd_group = g_ufdd.group_info;
+        while (ufd_group) {
+                char num[32];
+
+                if (space)
+                        fputc(' ', f);
+
+                snprintf(num, sizeof(num), "%d", ufd_group->grp_id);
+
+                fputs(num, f);
+                space = true;
+
+                ufd_group = ufd_group->next_group;
+        }
+
+        fprintf(f, "\n");
+
+        r = fflush_and_check(f);
+        if (r < 0) {
+                log_error("Failed to save ufd data to %s: %s", g_ufdd.state_file, strerror(-r));
+                unlink(g_ufdd.state_file);
+                unlink(temp_path);
+                return r;
+        }
+
+        if (rename(temp_path, g_ufdd.state_file) < 0) {
+                r = -errno;
+                unlink(g_ufdd.state_file);
+                unlink(temp_path);
+                return r;
+        }
+
+        return 0;
+}
+
+static int ufd_group_save(UfddGroup *ufd_group) {
+        _cleanup_free_ char *temp_path = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        UfddPort *ufd_port;
+        bool space;
+        int r;
+
+        assert(ufd_group);
+        assert(ufd_group->state_file);
+
+        r = fopen_temporary(ufd_group->state_file, &f, &temp_path);
+        if (r < 0)
+                return r;
+
+        fchmod(fileno(f), 0644);
+
+        fprintf(f,
+                "# This is private data. Do not parse.\n"
+                "GROUP_STATE=configured\n");
+
+        if (ufd_group->config_file)
+                fprintf(f, "CONFIG_FILE=%s\n", ufd_group->config_file);
+
+        fputs("UPLINKS=", f);
+        space = false;
+
+        ufd_port = ufd_group->up_link_ports;
+        while (ufd_port) {
+                char num[32];
+
+                if (space)
+                        fputc(' ', f);
+
+                snprintf(num, sizeof(num), "%d", ufd_port->if_index);
+
+                fputs(num, f);
+                space = true;
+
+                ufd_port = ufd_port->next_port;
+        }
+
+        fprintf(f, "\n");
+
+        fputs("DOWNLINKS=", f);
+        space = false;
+
+        ufd_port = ufd_group->down_link_ports;
+        while (ufd_port) {
+                char num[32];
+
+                if (space)
+                        fputc(' ', f);
+
+                snprintf(num, sizeof(num), "%d", ufd_port->if_index);
+
+                fputs(num, f);
+
+                space = true;
+
+                ufd_port = ufd_port->next_port;
+        }
+
+        fprintf(f, "\n");
+
+        r = fflush_and_check(f);
+        if (r < 0) {
+                log_error("Failed to save group data to %s: %s", ufd_group->state_file, strerror(-r));
+                unlink(ufd_group->state_file);
+                unlink(temp_path);
+                return r;
+        }
+
+        if (rename(temp_path, ufd_group->state_file) < 0) {
+                r = -errno;
+                unlink(ufd_group->state_file);
+                unlink(temp_path);
+                return r;
+        }
+
+        r = ufd_daemon_save();
+        if (r < 0)
+               return r;
+
+        return 0;
+}
+
+int ufd_daemon_set_group(int group_id,
+                         char *config_file,
+                         char *up_links,
+                         char *down_links) {
+        uint32_t uplink_count = 0;
+        uint32_t downlink_count = 0;
+        uint32_t *uplink_ptr = NULL;
+        uint32_t *downlink_ptr = NULL;
+        UfddGroup *ufd_group;
+        int r = 0;
+
+        if (group_id < 0) {
+                log_error("UFD: Group ID should be a positive number. Got: %d", group_id);
+                return -EINVAL;
+        }
+
+        ufd_group = get_group(group_id);
+        if (ufd_group) {
+                log_error("UFD: Group %d already configured", group_id);
+                return -EEXIST;
+        }
+
+        if (!up_links) {
+                log_error("UFD: Uplink port list is empty for group %d", group_id);
+                return -EINVAL;
+        }
+
+        if (!down_links) {
+                log_error("UFD: Downlink port list is empty for group %d", group_id);
+                return -EINVAL;
+        }
+
+        r = parse_ports_list(up_links, &uplink_ptr, &uplink_count);
+        if (r < 0) {
+                free(uplink_ptr);
+                return r;
+        }
+
+        r = parse_ports_list(down_links, &downlink_ptr, &downlink_count);
+        if (r < 0) {
+                free(uplink_ptr);
+                free(downlink_ptr);
+                return r;
+        }
+
+        r = ufd_group_add(group_id, uplink_ptr, uplink_count, downlink_ptr, downlink_count);
+        if (r < 0) {
+                free(uplink_ptr);
+                free(downlink_ptr);
+                return r;
+        }
+
+        ufd_group = get_group(group_id);
+        if (!ufd_group) {
+                log_error("UFD: Group %d not found", group_id);
+                free(uplink_ptr);
+                free(downlink_ptr);
+                return -EINVAL;
+        }
+
+        r = asprintf(&ufd_group->state_file, "/run/systemd/netif/ufd/groups/%d", group_id);
+        if (r < 0) {
+                free(uplink_ptr);
+                free(downlink_ptr);
+                return -ENOMEM;
+        }
+
+        ufd_group->config_file = malloc(strlen(config_file) + 1);
+        if (!ufd_group->config_file) {
+                free(uplink_ptr);
+                free(downlink_ptr);
+                return -ENOMEM;
+        }
+
+        strncpy(ufd_group->config_file, config_file, strlen(config_file) + 1);
+
+        ufd_group_save(ufd_group);
+
+        free(uplink_ptr);
+        free(downlink_ptr);
+
+        return r;
+}
+
+int ufd_daemon_init(void) {
+        int r;
+
+        if (!g_ufdd.rtnl) {
+                r = monitoring_init(&g_ufdd);
+                if (r < 0) {
+                        log_error("UFD: Could not init the UFD daemon");
+                        return r;
+                }
+
+                g_ufdd.state_file = strdup("/run/systemd/netif/ufd/state");
+                if (!g_ufdd.state_file) {
+                        log_error("UFD: Could not init the UFD daemon");
+                        return -ENOMEM;
+                }
+        }
+
+        return 0;
+}
+
+void ufd_daemon_close(void) {
+        sd_rtnl_unref(g_ufdd.rtnl);
+        ufd_db_cleanup();
+
+        unlink(g_ufdd.state_file);
+        free(g_ufdd.state_file);
+}
diff --git a/src/network/networkd-ufd-daemon.h b/src/network/networkd-ufd-daemon.h
new file mode 100644
index 0000000..b625d6f
--- /dev/null
+++ b/src/network/networkd-ufd-daemon.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+    This file is part of systemd.
+
+    Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+    systemd is free software; you can redistribute it and/or modify it
+    under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    systemd is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+/* Init the Uplink failure detection daemon. */
+int ufd_daemon_init(void);
+
+/* Close the Uplink failure detection daemon. */
+void ufd_daemon_close(void);
+
+/* Set Uplink failure detection group. */
+int ufd_daemon_set_group(int group_id,
+                         char *config_file,
+                         char *up_links,
+                         char *down_links);
diff --git a/src/network/networkd.c b/src/network/networkd.c
index ced319d..c475582 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -69,6 +69,13 @@ int main(int argc, char *argv[]) {
                 log_error("Could not create runtime directory 'lldp': %s",
                           strerror(-r));
 
+        r = mkdir_safe_label("/run/systemd/netif/ufd", 0755, uid, gid);
+        if (r < 0)
+                log_error_errno(r, "Could not create runtime directory 'ufd': %m");
+
+        r = mkdir_safe_label("/run/systemd/netif/ufd/groups", 0755, uid, gid);
+        if (r < 0)
+                log_error_errno(r, "Could not create runtime directory 'ufd': %m");
 
         r = drop_privileges(uid, gid,
                             (1ULL << CAP_NET_ADMIN) |
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 719a75b..bd40143 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -206,8 +206,13 @@ struct Manager {
 
         char *state_file;
 
+        unsigned links_to_configure;
+        bool groups_configured;
+
         Hashmap *links;
         Hashmap *netdevs;
+        Hashmap *group_netdevs;
+
         LIST_HEAD(Network, networks);
         LIST_HEAD(AddressPool, address_pools);
 
@@ -226,6 +231,7 @@ bool manager_should_reload(Manager *m);
 
 int manager_rtnl_enumerate_links(Manager *m);
 int manager_rtnl_enumerate_addresses(Manager *m);
+int manager_enumerate_groups(Manager *m);
 
 int manager_rtnl_listen(Manager *m);
 int manager_udev_listen(Manager *m);
diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h
index 027730d..693db6a 100644
--- a/src/systemd/sd-network.h
+++ b/src/systemd/sd-network.h
@@ -141,6 +141,26 @@ int sd_network_monitor_get_events(sd_network_monitor *m);
 /* Get timeout for poll(), as usec value relative to CLOCK_MONOTONIC's epoch */
 int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec);
 
+/* Get setup state for uplink failure detection group_id.
+ * Possible states:
+ *   configured: link configured successfully
+ * Possible return codes:
+ *   -ENODATA: networkd is not aware of the group_id
+ */
+int sd_network_ufd_get_setup_state(int group_id, char **state);
+
+/* Get path to .ufd file applied to group_id */
+int sd_network_ufd_get_config_file(int group_id, char **filename);
+
+/* Get uplinks for an uplink failure detection group. */
+int sd_network_ufd_get_uplinks(int group_id, char ***uplinks);
+
+/* Get downlinks for an uplink failure detection group. */
+int sd_network_ufd_get_downlinks(int group_id, char ***downlinks);
+
+/* Get list of groups configured by the system */
+int sd_network_ufd_get_group_list(char ***groups);
+
 _SD_END_DECLARATIONS;
 
 #endif
-- 
1.9.3



More information about the systemd-devel mailing list