rule: two boolean parameters with a flags field
[oweals/relayd.git] / route.c
diff --git a/route.c b/route.c
index 25f949e3f27bbacdb5fcda626eabf6cd6e7b597b..abe026310dfff7d6064c9a85bb799114e7895902 100644 (file)
--- a/route.c
+++ b/route.c
@@ -42,6 +42,70 @@ static void rtnl_flush(void)
        close(fd);
 }
 
+enum {
+       RULE_F_ADD = (1 << 0),
+       RULE_F_DEFGW_WORKAROUND = (1 << 1),
+};
+
+static void
+rtnl_rule_request(struct relayd_interface *rif, int flags)
+{
+       static struct {
+               struct nlmsghdr nl;
+               struct rtmsg rt;
+               struct {
+                       struct rtattr rta;
+                       int table;
+               } __packed table;
+               struct {
+                       struct rtattr rta;
+                       char ifname[IFNAMSIZ + 1];
+               } __packed dev;
+       } __packed req = {
+               .rt = {
+                       .rtm_family = AF_INET,
+                       .rtm_table = RT_TABLE_UNSPEC,
+                       .rtm_scope = RT_SCOPE_UNIVERSE,
+                       .rtm_protocol = RTPROT_BOOT,
+               },
+               .table.rta = {
+                       .rta_type = FRA_TABLE,
+                       .rta_len = sizeof(req.table),
+               },
+       };
+
+       int padding = sizeof(req.dev.ifname);
+
+       if (!(flags & RULE_F_DEFGW_WORKAROUND)) {
+               req.dev.rta.rta_type = FRA_IFNAME;
+               padding -= strlen(rif->ifname) + 1;
+               strcpy(req.dev.ifname, rif->ifname);
+               req.dev.rta.rta_len = sizeof(req.dev.rta) + strlen(rif->ifname) + 1;
+       } else {
+               req.dev.rta.rta_type = FRA_PRIORITY;
+               req.dev.rta.rta_len = sizeof(req.dev.rta) + sizeof(uint32_t);
+               padding -= sizeof(uint32_t);
+               *((uint32_t *) &req.dev.ifname) = 1;
+       }
+       req.table.table = rif->rt_table;
+       req.nl.nlmsg_len = sizeof(req) - padding;
+
+       req.nl.nlmsg_flags = NLM_F_REQUEST;
+       if (flags & RULE_F_ADD) {
+               req.nl.nlmsg_type = RTM_NEWRULE;
+               req.nl.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+
+               req.rt.rtm_type = RTN_UNICAST;
+       } else {
+               req.nl.nlmsg_type = RTM_DELRULE;
+               req.rt.rtm_type = RTN_UNSPEC;
+       }
+
+       send(rtnl_sock.fd, &req, req.nl.nlmsg_len, 0);
+       rtnl_flush();
+}
+
+
 static void
 rtnl_route_request(struct relayd_interface *rif, struct relayd_host *host,
                   struct relayd_route *route, bool add)
@@ -131,59 +195,11 @@ rtnl_route_request(struct relayd_interface *rif, struct relayd_host *host,
        }
 
        req.nl.nlmsg_len = pktlen;
+       if (route)
+               rtnl_rule_request(rif, RULE_F_DEFGW_WORKAROUND | RULE_F_ADD);
        send(rtnl_sock.fd, &req, pktlen, 0);
-       rtnl_flush();
-}
-
-static void rtnl_rule_request(struct relayd_interface *rif, bool add)
-{
-       static struct {
-               struct nlmsghdr nl;
-               struct rtmsg rt;
-               struct {
-                       struct rtattr rta;
-                       int table;
-               } __packed table;
-               struct {
-                       struct rtattr rta;
-                       char ifname[IFNAMSIZ + 1];
-               } __packed dev;
-       } __packed req = {
-               .rt = {
-                       .rtm_family = AF_INET,
-                       .rtm_table = RT_TABLE_UNSPEC,
-                       .rtm_scope = RT_SCOPE_UNIVERSE,
-                       .rtm_protocol = RTPROT_BOOT,
-               },
-               .table.rta = {
-                       .rta_type = FRA_TABLE,
-                       .rta_len = sizeof(req.table),
-               },
-               .dev.rta = {
-                       .rta_type = FRA_IFNAME,
-               },
-       };
-
-       int padding = sizeof(req.dev.ifname);
-       padding -= strlen(rif->ifname) + 1;
-
-       strcpy(req.dev.ifname, rif->ifname);
-       req.dev.rta.rta_len = sizeof(req.dev.rta) + strlen(rif->ifname) + 1;
-       req.table.table = rif->rt_table;
-       req.nl.nlmsg_len = sizeof(req) - padding;
-
-       req.nl.nlmsg_flags = NLM_F_REQUEST;
-       if (add) {
-               req.nl.nlmsg_type = RTM_NEWRULE;
-               req.nl.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
-
-               req.rt.rtm_type = RTN_UNICAST;
-       } else {
-               req.nl.nlmsg_type = RTM_DELRULE;
-               req.rt.rtm_type = RTN_UNSPEC;
-       }
-
-       send(rtnl_sock.fd, &req, req.nl.nlmsg_len, 0);
+       if (route)
+               rtnl_rule_request(rif, RULE_F_DEFGW_WORKAROUND);
        rtnl_flush();
 }
 
@@ -203,12 +219,12 @@ rtnl_route_set(struct relayd_host *host, struct relayd_route *route, bool add)
 void relayd_add_interface_routes(struct relayd_interface *rif)
 {
        rif->rt_table = route_table++;
-       rtnl_rule_request(rif, true);
+       rtnl_rule_request(rif, RULE_F_ADD);
 }
 
 void relayd_del_interface_routes(struct relayd_interface *rif)
 {
-       rtnl_rule_request(rif, false);
+       rtnl_rule_request(rif, 0);
 }
 
 #ifndef NDA_RTA
@@ -313,21 +329,28 @@ static void rtnl_cb(struct uloop_fd *fd, unsigned int events)
        } while (1);
 }
 
-int relayd_rtnl_init(void)
+static void rtnl_dump_request(int nlmsg_type)
 {
-       struct sockaddr_nl snl_local;
        static struct {
                struct nlmsghdr nlh;
                struct rtgenmsg g;
        } req = {
                .nlh = {
                        .nlmsg_len = sizeof(req),
-                       .nlmsg_type = RTM_GETNEIGH,
                        .nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST,
                        .nlmsg_pid = 0,
                },
                .g.rtgen_family = AF_INET,
        };
+       req.nlh.nlmsg_type = nlmsg_type;
+       req.nlh.nlmsg_seq = rtnl_seq;
+       send(rtnl_sock.fd, &req, sizeof(req), 0);
+       rtnl_seq++;
+}
+
+int relayd_rtnl_init(void)
+{
+       struct sockaddr_nl snl_local;
 
        rtnl_sock.fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
        if (rtnl_sock.fd < 0) {
@@ -348,8 +371,7 @@ int relayd_rtnl_init(void)
 
        rtnl_seq = time(NULL);
        rtnl_dump_seq = rtnl_seq;
-       req.nlh.nlmsg_seq = rtnl_seq;
-       send(rtnl_sock.fd, &req, sizeof(req), 0);
+       rtnl_dump_request(RTM_GETNEIGH);
 
        return 0;
 }