LCOV - code coverage report
Current view: top level - network - networkd-routing-policy-rule.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 171 787 21.7 %
Date: 2019-08-23 13:36:53 Functions: 7 32 21.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 107 797 13.4 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <net/if.h>
       4                 :            : #include <linux/fib_rules.h>
       5                 :            : 
       6                 :            : #include "af-list.h"
       7                 :            : #include "alloc-util.h"
       8                 :            : #include "conf-parser.h"
       9                 :            : #include "fileio.h"
      10                 :            : #include "ip-protocol-list.h"
      11                 :            : #include "networkd-routing-policy-rule.h"
      12                 :            : #include "netlink-util.h"
      13                 :            : #include "networkd-manager.h"
      14                 :            : #include "networkd-util.h"
      15                 :            : #include "parse-util.h"
      16                 :            : #include "socket-util.h"
      17                 :            : #include "string-util.h"
      18                 :            : #include "strv.h"
      19                 :            : 
      20                 :         28 : int routing_policy_rule_new(RoutingPolicyRule **ret) {
      21                 :            :         RoutingPolicyRule *rule;
      22                 :            : 
      23                 :         28 :         rule = new(RoutingPolicyRule, 1);
      24         [ -  + ]:         28 :         if (!rule)
      25                 :          0 :                 return -ENOMEM;
      26                 :            : 
      27                 :         28 :         *rule = (RoutingPolicyRule) {
      28                 :            :                 .table = RT_TABLE_MAIN,
      29                 :            :         };
      30                 :            : 
      31                 :         28 :         *ret = rule;
      32                 :         28 :         return 0;
      33                 :            : }
      34                 :            : 
      35                 :         28 : void routing_policy_rule_free(RoutingPolicyRule *rule) {
      36                 :            : 
      37         [ -  + ]:         28 :         if (!rule)
      38                 :          0 :                 return;
      39                 :            : 
      40         [ -  + ]:         28 :         if (rule->network) {
      41   [ #  #  #  #  :          0 :                 LIST_REMOVE(rules, rule->network->rules, rule);
             #  #  #  # ]
      42         [ #  # ]:          0 :                 assert(rule->network->n_rules > 0);
      43                 :          0 :                 rule->network->n_rules--;
      44                 :            : 
      45         [ #  # ]:          0 :                 if (rule->section)
      46                 :          0 :                         hashmap_remove(rule->network->rules_by_section, rule->section);
      47                 :            :         }
      48                 :            : 
      49         [ -  + ]:         28 :         if (rule->manager) {
      50         [ #  # ]:          0 :                 if (set_get(rule->manager->rules, rule) == rule)
      51                 :          0 :                         set_remove(rule->manager->rules, rule);
      52         [ #  # ]:          0 :                 if (set_get(rule->manager->rules_foreign, rule) == rule)
      53                 :          0 :                         set_remove(rule->manager->rules_foreign, rule);
      54                 :            :         }
      55                 :            : 
      56                 :         28 :         network_config_section_free(rule->section);
      57                 :         28 :         free(rule->iif);
      58                 :         28 :         free(rule->oif);
      59                 :         28 :         free(rule);
      60                 :            : }
      61                 :            : 
      62                 :          0 : static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *src) {
      63                 :          0 :         _cleanup_free_ char *iif = NULL, *oif = NULL;
      64                 :            : 
      65         [ #  # ]:          0 :         assert(dest);
      66         [ #  # ]:          0 :         assert(src);
      67                 :            : 
      68         [ #  # ]:          0 :         if (src->iif) {
      69                 :          0 :                 iif = strdup(src->iif);
      70         [ #  # ]:          0 :                 if (!iif)
      71                 :          0 :                         return -ENOMEM;
      72                 :            :         }
      73                 :            : 
      74         [ #  # ]:          0 :         if (src->oif) {
      75                 :          0 :                 oif = strdup(src->oif);
      76         [ #  # ]:          0 :                 if (!oif)
      77                 :          0 :                         return -ENOMEM;
      78                 :            :         }
      79                 :            : 
      80                 :          0 :         dest->family = src->family;
      81                 :          0 :         dest->from = src->from;
      82                 :          0 :         dest->from_prefixlen = src->from_prefixlen;
      83                 :          0 :         dest->to = src->to;
      84                 :          0 :         dest->to_prefixlen = src->to_prefixlen;
      85                 :          0 :         dest->invert_rule = src->invert_rule;
      86                 :          0 :         dest->tos = src->tos;
      87                 :          0 :         dest->fwmark = src->fwmark;
      88                 :          0 :         dest->fwmask = src->fwmask;
      89                 :          0 :         dest->priority = src->priority;
      90                 :          0 :         dest->table = src->table;
      91                 :          0 :         dest->iif = TAKE_PTR(iif);
      92                 :          0 :         dest->oif = TAKE_PTR(oif);
      93                 :          0 :         dest->protocol = src->protocol;
      94                 :          0 :         dest->sport = src->sport;
      95                 :          0 :         dest->dport = src->dport;
      96                 :            : 
      97                 :          0 :         return 0;
      98                 :            : }
      99                 :            : 
     100                 :         28 : static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
     101         [ -  + ]:         28 :         assert(rule);
     102                 :            : 
     103                 :         28 :         siphash24_compress(&rule->family, sizeof(rule->family), state);
     104                 :            : 
     105         [ +  - ]:         28 :         switch (rule->family) {
     106                 :         28 :         case AF_INET:
     107                 :            :         case AF_INET6:
     108                 :            : 
     109                 :         28 :                 siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
     110                 :         28 :                 siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
     111                 :            : 
     112                 :         28 :                 siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
     113                 :         28 :                 siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
     114                 :            : 
     115                 :         28 :                 siphash24_compress_boolean(rule->invert_rule, state);
     116                 :            : 
     117                 :         28 :                 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
     118                 :         28 :                 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
     119                 :         28 :                 siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
     120                 :         28 :                 siphash24_compress(&rule->priority, sizeof(rule->priority), state);
     121                 :         28 :                 siphash24_compress(&rule->table, sizeof(rule->table), state);
     122                 :            : 
     123                 :         28 :                 siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
     124                 :         28 :                 siphash24_compress(&rule->sport, sizeof(rule->sport), state);
     125                 :         28 :                 siphash24_compress(&rule->dport, sizeof(rule->dport), state);
     126                 :            : 
     127         [ +  + ]:         28 :                 if (rule->iif)
     128                 :          8 :                         siphash24_compress(rule->iif, strlen(rule->iif), state);
     129                 :            : 
     130         [ +  + ]:         28 :                 if (rule->oif)
     131                 :          8 :                         siphash24_compress(rule->oif, strlen(rule->oif), state);
     132                 :            : 
     133                 :         28 :                 break;
     134                 :          0 :         default:
     135                 :            :                 /* treat any other address family as AF_UNSPEC */
     136                 :          0 :                 break;
     137                 :            :         }
     138                 :         28 : }
     139                 :            : 
     140                 :          0 : static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
     141                 :            :         int r;
     142                 :            : 
     143         [ #  # ]:          0 :         r = CMP(a->family, b->family);
     144         [ #  # ]:          0 :         if (r != 0)
     145                 :          0 :                 return r;
     146                 :            : 
     147         [ #  # ]:          0 :         switch (a->family) {
     148                 :          0 :         case AF_INET:
     149                 :            :         case AF_INET6:
     150         [ #  # ]:          0 :                 r = CMP(a->from_prefixlen, b->from_prefixlen);
     151         [ #  # ]:          0 :                 if (r != 0)
     152                 :          0 :                         return r;
     153                 :            : 
     154         [ #  # ]:          0 :                 r = CMP(a->to_prefixlen, b->to_prefixlen);
     155         [ #  # ]:          0 :                 if (r != 0)
     156                 :          0 :                         return r;
     157                 :            : 
     158         [ #  # ]:          0 :                 r = CMP(a->invert_rule, b->invert_rule);
     159         [ #  # ]:          0 :                 if (r != 0)
     160                 :          0 :                         return r;
     161                 :            : 
     162         [ #  # ]:          0 :                 r = CMP(a->tos, b->tos);
     163         [ #  # ]:          0 :                 if (r != 0)
     164                 :          0 :                         return r;
     165                 :            : 
     166         [ #  # ]:          0 :                 r = CMP(a->fwmark, b->fwmark);
     167         [ #  # ]:          0 :                 if (r != 0)
     168                 :          0 :                         return r;
     169                 :            : 
     170         [ #  # ]:          0 :                 r = CMP(a->fwmask, b->fwmask);
     171         [ #  # ]:          0 :                 if (r != 0)
     172                 :          0 :                         return r;
     173                 :            : 
     174         [ #  # ]:          0 :                 r = CMP(a->priority, b->priority);
     175         [ #  # ]:          0 :                 if (r != 0)
     176                 :          0 :                         return r;
     177                 :            : 
     178         [ #  # ]:          0 :                 r = CMP(a->table, b->table);
     179         [ #  # ]:          0 :                 if (r != 0)
     180                 :          0 :                         return r;
     181                 :            : 
     182                 :          0 :                 r = strcmp_ptr(a->iif, b->iif);
     183         [ #  # ]:          0 :                 if (!r)
     184                 :          0 :                         return r;
     185                 :            : 
     186                 :          0 :                 r = strcmp_ptr(a->oif, b->oif);
     187         [ #  # ]:          0 :                 if (!r)
     188                 :          0 :                         return r;
     189                 :            : 
     190         [ #  # ]:          0 :                 r = CMP(a->protocol, b->protocol);
     191         [ #  # ]:          0 :                 if (r != 0)
     192                 :          0 :                         return r;
     193                 :            : 
     194                 :          0 :                 r = memcmp(&a->sport, &b->sport, sizeof(a->sport));
     195         [ #  # ]:          0 :                 if (r != 0)
     196                 :          0 :                         return r;
     197                 :            : 
     198                 :          0 :                 r = memcmp(&a->dport, &b->dport, sizeof(a->dport));
     199         [ #  # ]:          0 :                 if (r != 0)
     200                 :          0 :                         return r;
     201                 :            : 
     202                 :          0 :                 r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
     203         [ #  # ]:          0 :                 if (r != 0)
     204                 :          0 :                         return r;
     205                 :            : 
     206                 :          0 :                 return memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
     207                 :            : 
     208                 :          0 :         default:
     209                 :            :                 /* treat any other address family as AF_UNSPEC */
     210                 :          0 :                 return 0;
     211                 :            :         }
     212                 :            : }
     213                 :            : 
     214                 :            : DEFINE_PRIVATE_HASH_OPS(routing_policy_rule_hash_ops, RoutingPolicyRule, routing_policy_rule_hash_func, routing_policy_rule_compare_func);
     215                 :            : 
     216                 :          0 : int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
     217                 :            : 
     218                 :            :         RoutingPolicyRule *existing;
     219                 :            : 
     220         [ #  # ]:          0 :         assert(m);
     221                 :            : 
     222                 :          0 :         existing = set_get(m->rules, rule);
     223         [ #  # ]:          0 :         if (existing) {
     224         [ #  # ]:          0 :                 if (ret)
     225                 :          0 :                         *ret = existing;
     226                 :          0 :                 return 1;
     227                 :            :         }
     228                 :            : 
     229                 :          0 :         existing = set_get(m->rules_foreign, rule);
     230         [ #  # ]:          0 :         if (existing) {
     231         [ #  # ]:          0 :                 if (ret)
     232                 :          0 :                         *ret = existing;
     233                 :          0 :                 return 0;
     234                 :            :         }
     235                 :            : 
     236                 :          0 :         return -ENOENT;
     237                 :            : }
     238                 :            : 
     239                 :          0 : int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
     240                 :            :         int r;
     241                 :            : 
     242         [ #  # ]:          0 :         assert(m);
     243                 :            : 
     244         [ #  # ]:          0 :         if (set_contains(m->rules_foreign, rule)) {
     245                 :          0 :                 set_remove(m->rules_foreign, rule);
     246                 :            : 
     247                 :          0 :                 r = set_ensure_allocated(&m->rules, &routing_policy_rule_hash_ops);
     248         [ #  # ]:          0 :                 if (r < 0)
     249                 :          0 :                         return r;
     250                 :            : 
     251                 :          0 :                 r = set_put(m->rules, rule);
     252         [ #  # ]:          0 :                 if (r < 0)
     253                 :          0 :                         return r;
     254         [ #  # ]:          0 :                 if (r == 0)
     255                 :          0 :                         routing_policy_rule_free(rule);
     256                 :            :         }
     257                 :            : 
     258                 :          0 :         return -ENOENT;
     259                 :            : }
     260                 :            : 
     261                 :          0 : static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, RoutingPolicyRule **ret) {
     262                 :          0 :         _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
     263                 :            :         int r;
     264                 :            : 
     265         [ #  # ]:          0 :         assert(m);
     266         [ #  # ]:          0 :         assert(rules);
     267         [ #  # ]:          0 :         assert(in);
     268                 :            : 
     269                 :          0 :         r = routing_policy_rule_new(&rule);
     270         [ #  # ]:          0 :         if (r < 0)
     271                 :          0 :                 return r;
     272                 :            : 
     273                 :          0 :         rule->manager = m;
     274                 :            : 
     275                 :          0 :         r = routing_policy_rule_copy(rule, in);
     276         [ #  # ]:          0 :         if (r < 0)
     277                 :          0 :                 return r;
     278                 :            : 
     279                 :          0 :         r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
     280         [ #  # ]:          0 :         if (r < 0)
     281                 :          0 :                 return r;
     282                 :            : 
     283                 :          0 :         r = set_put(*rules, rule);
     284         [ #  # ]:          0 :         if (r < 0)
     285                 :          0 :                 return r;
     286         [ #  # ]:          0 :         if (r == 0)
     287                 :          0 :                 return -EEXIST;
     288                 :            : 
     289         [ #  # ]:          0 :         if (ret)
     290                 :          0 :                 *ret = rule;
     291                 :            : 
     292                 :          0 :         TAKE_PTR(rule);
     293                 :          0 :         return 0;
     294                 :            : }
     295                 :            : 
     296                 :          0 : static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
     297                 :          0 :         return routing_policy_rule_add_internal(m, &m->rules, rule, ret);
     298                 :            : }
     299                 :            : 
     300                 :          0 : int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
     301                 :          0 :         return routing_policy_rule_add_internal(m, &m->rules_foreign, rule, ret);
     302                 :            : }
     303                 :            : 
     304                 :          0 : static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
     305                 :            :         int r;
     306                 :            : 
     307         [ #  # ]:          0 :         assert(m);
     308         [ #  # ]:          0 :         assert(link);
     309         [ #  # ]:          0 :         assert(link->ifname);
     310                 :            : 
     311                 :          0 :         link->routing_policy_rule_remove_messages--;
     312                 :            : 
     313   [ #  #  #  # ]:          0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
     314                 :          0 :                 return 1;
     315                 :            : 
     316                 :          0 :         r = sd_netlink_message_get_errno(m);
     317         [ #  # ]:          0 :         if (r < 0)
     318   [ #  #  #  # ]:          0 :                 log_link_warning_errno(link, r, "Could not drop routing policy rule: %m");
     319                 :            : 
     320                 :          0 :         return 1;
     321                 :            : }
     322                 :            : 
     323                 :          0 : int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback) {
     324                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
     325                 :            :         int r;
     326                 :            : 
     327         [ #  # ]:          0 :         assert(routing_policy_rule);
     328         [ #  # ]:          0 :         assert(link);
     329         [ #  # ]:          0 :         assert(link->manager);
     330         [ #  # ]:          0 :         assert(link->manager->rtnl);
     331         [ #  # ]:          0 :         assert(link->ifindex > 0);
     332   [ #  #  #  # ]:          0 :         assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6));
     333                 :            : 
     334                 :          0 :         r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
     335         [ #  # ]:          0 :         if (r < 0)
     336         [ #  # ]:          0 :                 return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
     337                 :            : 
     338         [ #  # ]:          0 :         if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) {
     339                 :          0 :                 r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
     340         [ #  # ]:          0 :                 if (r < 0)
     341         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
     342                 :            : 
     343                 :          0 :                 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
     344         [ #  # ]:          0 :                 if (r < 0)
     345         [ #  # ]:          0 :                         return log_error_errno(r, "Could not set source prefix length: %m");
     346                 :            :         }
     347                 :            : 
     348         [ #  # ]:          0 :         if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
     349                 :          0 :                 r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
     350         [ #  # ]:          0 :                 if (r < 0)
     351         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_DST attribute: %m");
     352                 :            : 
     353                 :          0 :                 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
     354         [ #  # ]:          0 :                 if (r < 0)
     355         [ #  # ]:          0 :                         return log_error_errno(r, "Could not set destination prefix length: %m");
     356                 :            :         }
     357                 :            : 
     358         [ #  # ]:          0 :         r = netlink_call_async(link->manager->rtnl, NULL, m,
     359                 :            :                                callback ?: routing_policy_rule_remove_handler,
     360                 :            :                                link_netlink_destroy_callback, link);
     361         [ #  # ]:          0 :         if (r < 0)
     362         [ #  # ]:          0 :                 return log_error_errno(r, "Could not send rtnetlink message: %m");
     363                 :            : 
     364                 :          0 :         link_ref(link);
     365                 :            : 
     366                 :          0 :         return 0;
     367                 :            : }
     368                 :            : 
     369                 :          0 : static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
     370                 :          0 :         _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
     371                 :          0 :         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
     372                 :            :         int r;
     373                 :            : 
     374         [ #  # ]:          0 :         assert(network);
     375         [ #  # ]:          0 :         assert(ret);
     376         [ #  # ]:          0 :         assert(!!filename == (section_line > 0));
     377                 :            : 
     378         [ #  # ]:          0 :         if (filename) {
     379                 :          0 :                 r = network_config_section_new(filename, section_line, &n);
     380         [ #  # ]:          0 :                 if (r < 0)
     381                 :          0 :                         return r;
     382                 :            : 
     383                 :          0 :                 rule = hashmap_get(network->rules_by_section, n);
     384         [ #  # ]:          0 :                 if (rule) {
     385                 :          0 :                         *ret = TAKE_PTR(rule);
     386                 :            : 
     387                 :          0 :                         return 0;
     388                 :            :                 }
     389                 :            :         }
     390                 :            : 
     391                 :          0 :         r = routing_policy_rule_new(&rule);
     392         [ #  # ]:          0 :         if (r < 0)
     393                 :          0 :                 return r;
     394                 :            : 
     395                 :          0 :         rule->network = network;
     396   [ #  #  #  #  :          0 :         LIST_APPEND(rules, network->rules, rule);
          #  #  #  #  #  
                #  #  # ]
     397                 :          0 :         network->n_rules++;
     398                 :            : 
     399         [ #  # ]:          0 :         if (filename) {
     400                 :          0 :                 rule->section = TAKE_PTR(n);
     401                 :            : 
     402                 :          0 :                 r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
     403         [ #  # ]:          0 :                 if (r < 0)
     404                 :          0 :                         return r;
     405                 :            : 
     406                 :          0 :                 r = hashmap_put(network->rules_by_section, rule->section, rule);
     407         [ #  # ]:          0 :                 if (r < 0)
     408                 :          0 :                         return r;
     409                 :            :         }
     410                 :            : 
     411                 :          0 :         *ret = TAKE_PTR(rule);
     412                 :            : 
     413                 :          0 :         return 0;
     414                 :            : }
     415                 :            : 
     416                 :          0 : static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
     417                 :            :         int r;
     418                 :            : 
     419         [ #  # ]:          0 :         assert(rtnl);
     420         [ #  # ]:          0 :         assert(m);
     421         [ #  # ]:          0 :         assert(link);
     422         [ #  # ]:          0 :         assert(link->ifname);
     423         [ #  # ]:          0 :         assert(link->routing_policy_rule_messages > 0);
     424                 :            : 
     425                 :          0 :         link->routing_policy_rule_messages--;
     426                 :            : 
     427   [ #  #  #  # ]:          0 :         if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
     428                 :          0 :                 return 1;
     429                 :            : 
     430                 :          0 :         r = sd_netlink_message_get_errno(m);
     431   [ #  #  #  # ]:          0 :         if (r < 0 && r != -EEXIST) {
     432   [ #  #  #  # ]:          0 :                 log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
     433                 :          0 :                 link_enter_failed(link);
     434                 :          0 :                 return 1;
     435                 :            :         }
     436                 :            : 
     437         [ #  # ]:          0 :         if (link->routing_policy_rule_messages == 0) {
     438   [ #  #  #  # ]:          0 :                 log_link_debug(link, "Routing policy rule configured");
     439                 :          0 :                 link->routing_policy_rules_configured = true;
     440                 :          0 :                 link_check_ready(link);
     441                 :            :         }
     442                 :            : 
     443                 :          0 :         return 1;
     444                 :            : }
     445                 :            : 
     446                 :          0 : int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
     447                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
     448                 :            :         int r;
     449                 :            : 
     450         [ #  # ]:          0 :         assert(rule);
     451         [ #  # ]:          0 :         assert(link);
     452         [ #  # ]:          0 :         assert(link->ifindex > 0);
     453         [ #  # ]:          0 :         assert(link->manager);
     454         [ #  # ]:          0 :         assert(link->manager->rtnl);
     455                 :            : 
     456   [ #  #  #  # ]:          0 :         if (rule->family == AF_INET6 && link_sysctl_ipv6_enabled(link) == 0) {
     457   [ #  #  #  # ]:          0 :                 log_link_warning(link, "An IPv6 routing policy rule is requested, but IPv6 is disabled by sysctl, ignoring.");
     458                 :          0 :                 return 0;
     459                 :            :         }
     460                 :            : 
     461                 :          0 :         r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
     462         [ #  # ]:          0 :         if (r < 0)
     463         [ #  # ]:          0 :                 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
     464                 :            : 
     465         [ #  # ]:          0 :         if (in_addr_is_null(rule->family, &rule->from) == 0) {
     466                 :          0 :                 r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
     467         [ #  # ]:          0 :                 if (r < 0)
     468         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
     469                 :            : 
     470                 :          0 :                 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
     471         [ #  # ]:          0 :                 if (r < 0)
     472         [ #  # ]:          0 :                         return log_error_errno(r, "Could not set source prefix length: %m");
     473                 :            :         }
     474                 :            : 
     475         [ #  # ]:          0 :         if (in_addr_is_null(rule->family, &rule->to) == 0) {
     476                 :          0 :                 r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
     477         [ #  # ]:          0 :                 if (r < 0)
     478         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_DST attribute: %m");
     479                 :            : 
     480                 :          0 :                 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
     481         [ #  # ]:          0 :                 if (r < 0)
     482         [ #  # ]:          0 :                         return log_error_errno(r, "Could not set destination prefix length: %m");
     483                 :            :         }
     484                 :            : 
     485                 :          0 :         r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
     486         [ #  # ]:          0 :         if (r < 0)
     487         [ #  # ]:          0 :                 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
     488                 :            : 
     489         [ #  # ]:          0 :         if (rule->tos > 0) {
     490                 :          0 :                 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
     491         [ #  # ]:          0 :                 if (r < 0)
     492         [ #  # ]:          0 :                         return log_error_errno(r, "Could not set ip rule tos: %m");
     493                 :            :         }
     494                 :            : 
     495         [ #  # ]:          0 :         if (rule->table < 256) {
     496                 :          0 :                 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
     497         [ #  # ]:          0 :                 if (r < 0)
     498         [ #  # ]:          0 :                         return log_error_errno(r, "Could not set ip rule table: %m");
     499                 :            :         } else {
     500                 :          0 :                 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
     501         [ #  # ]:          0 :                 if (r < 0)
     502         [ #  # ]:          0 :                         return log_error_errno(r, "Could not set ip rule table: %m");
     503                 :            : 
     504                 :          0 :                 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
     505         [ #  # ]:          0 :                 if (r < 0)
     506         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
     507                 :            :         }
     508                 :            : 
     509         [ #  # ]:          0 :         if (rule->fwmark > 0) {
     510                 :          0 :                 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
     511         [ #  # ]:          0 :                 if (r < 0)
     512         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
     513                 :            :         }
     514                 :            : 
     515         [ #  # ]:          0 :         if (rule->fwmask > 0) {
     516                 :          0 :                 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
     517         [ #  # ]:          0 :                 if (r < 0)
     518         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
     519                 :            :         }
     520                 :            : 
     521         [ #  # ]:          0 :         if (rule->iif) {
     522                 :          0 :                 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
     523         [ #  # ]:          0 :                 if (r < 0)
     524         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
     525                 :            :         }
     526                 :            : 
     527         [ #  # ]:          0 :         if (rule->oif) {
     528                 :          0 :                 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
     529         [ #  # ]:          0 :                 if (r < 0)
     530         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
     531                 :            :         }
     532                 :            : 
     533                 :          0 :         r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
     534         [ #  # ]:          0 :         if (r < 0)
     535         [ #  # ]:          0 :                 return log_error_errno(r, "Could not append FRA_IP_PROTO attribute: %m");
     536                 :            : 
     537   [ #  #  #  # ]:          0 :         if (rule->sport.start != 0 || rule->sport.end != 0) {
     538                 :          0 :                 r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
     539         [ #  # ]:          0 :                 if (r < 0)
     540         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_SPORT_RANGE attribute: %m");
     541                 :            :         }
     542                 :            : 
     543   [ #  #  #  # ]:          0 :         if (rule->dport.start != 0 || rule->dport.end != 0) {
     544                 :          0 :                 r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
     545         [ #  # ]:          0 :                 if (r < 0)
     546         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m");
     547                 :            :         }
     548                 :            : 
     549         [ #  # ]:          0 :         if (rule->invert_rule) {
     550                 :          0 :                 r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
     551         [ #  # ]:          0 :                 if (r < 0)
     552         [ #  # ]:          0 :                         return log_error_errno(r, "Could not append FIB_RULE_INVERT attribute: %m");
     553                 :            :         }
     554                 :            : 
     555                 :          0 :         rule->link = link;
     556                 :            : 
     557         [ #  # ]:          0 :         r = netlink_call_async(link->manager->rtnl, NULL, m,
     558                 :            :                                callback ?: routing_policy_rule_handler,
     559                 :            :                                link_netlink_destroy_callback, link);
     560         [ #  # ]:          0 :         if (r < 0)
     561         [ #  # ]:          0 :                 return log_error_errno(r, "Could not send rtnetlink message: %m");
     562                 :            : 
     563                 :          0 :         link_ref(link);
     564                 :            : 
     565                 :          0 :         r = routing_policy_rule_add(link->manager, rule, NULL);
     566         [ #  # ]:          0 :         if (r < 0)
     567         [ #  # ]:          0 :                 return log_error_errno(r, "Could not add rule: %m");
     568                 :            : 
     569                 :          0 :         return 1;
     570                 :            : }
     571                 :            : 
     572                 :          0 : int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
     573                 :            :         int r;
     574                 :            : 
     575         [ #  # ]:          0 :         if (section_is_invalid(rule->section))
     576                 :          0 :                 return -EINVAL;
     577                 :            : 
     578   [ #  #  #  # ]:          0 :         if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) ||
     579   [ #  #  #  # ]:          0 :             (rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)))
     580         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     581                 :            :                                 "%s: address family specified by Family= conflicts with the address "
     582                 :            :                                 "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.",
     583                 :            :                                 rule->section->filename, rule->section->line);
     584                 :            : 
     585         [ #  # ]:          0 :         if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6)) {
     586         [ #  # ]:          0 :                 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule6 = NULL;
     587                 :            : 
     588         [ #  # ]:          0 :                 assert(rule->family == AF_UNSPEC);
     589                 :            : 
     590                 :            :                 /* When Family=both, we need to copy the section, AF_INET and AF_INET6. */
     591                 :            : 
     592                 :          0 :                 r = routing_policy_rule_new_static(rule->network, NULL, 0, &rule6);
     593         [ #  # ]:          0 :                 if (r < 0)
     594                 :          0 :                         return r;
     595                 :            : 
     596                 :          0 :                 r = routing_policy_rule_copy(rule6, rule);
     597         [ #  # ]:          0 :                 if (r < 0)
     598                 :          0 :                         return r;
     599                 :            : 
     600                 :          0 :                 rule->family = AF_INET;
     601                 :          0 :                 rule6->family = AF_INET6;
     602                 :            : 
     603                 :          0 :                 TAKE_PTR(rule6);
     604                 :            :         }
     605                 :            : 
     606         [ #  # ]:          0 :         if (rule->family == AF_UNSPEC) {
     607         [ #  # ]:          0 :                 if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6))
     608                 :          0 :                         rule->family = AF_INET6;
     609                 :            :                 else
     610                 :          0 :                         rule->family = AF_INET;
     611                 :            :         }
     612                 :            : 
     613                 :          0 :         return 0;
     614                 :            : }
     615                 :            : 
     616                 :         12 : static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
     617                 :         12 :         _cleanup_free_ char *f = NULL;
     618                 :            :         char *p;
     619                 :            :         int r;
     620                 :            : 
     621         [ -  + ]:         12 :         assert(s);
     622                 :            : 
     623                 :         12 :         f = strdup(s);
     624         [ -  + ]:         12 :         if (!f)
     625                 :          0 :                 return -ENOMEM;
     626                 :            : 
     627                 :         12 :         p = strchr(f, '/');
     628         [ +  + ]:         12 :         if (p)
     629                 :          4 :                 *p++ = '\0';
     630                 :            : 
     631                 :         12 :         r = safe_atou32(f, fwmark);
     632         [ -  + ]:         12 :         if (r < 0)
     633         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
     634                 :            : 
     635         [ +  + ]:         12 :         if (p) {
     636                 :          4 :                 r = safe_atou32(p, fwmask);
     637         [ -  + ]:          4 :                 if (r < 0)
     638         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
     639                 :            :         }
     640                 :            : 
     641                 :         12 :         return 0;
     642                 :            : }
     643                 :            : 
     644                 :          0 : int config_parse_routing_policy_rule_tos(
     645                 :            :                 const char *unit,
     646                 :            :                 const char *filename,
     647                 :            :                 unsigned line,
     648                 :            :                 const char *section,
     649                 :            :                 unsigned section_line,
     650                 :            :                 const char *lvalue,
     651                 :            :                 int ltype,
     652                 :            :                 const char *rvalue,
     653                 :            :                 void *data,
     654                 :            :                 void *userdata) {
     655                 :            : 
     656                 :          0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     657                 :          0 :         Network *network = userdata;
     658                 :            :         int r;
     659                 :            : 
     660         [ #  # ]:          0 :         assert(filename);
     661         [ #  # ]:          0 :         assert(section);
     662         [ #  # ]:          0 :         assert(lvalue);
     663         [ #  # ]:          0 :         assert(rvalue);
     664         [ #  # ]:          0 :         assert(data);
     665                 :            : 
     666                 :          0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     667         [ #  # ]:          0 :         if (r < 0)
     668                 :          0 :                 return r;
     669                 :            : 
     670                 :          0 :         r = safe_atou8(rvalue, &n->tos);
     671         [ #  # ]:          0 :         if (r < 0) {
     672         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
     673                 :          0 :                 return 0;
     674                 :            :         }
     675                 :            : 
     676                 :          0 :         n = NULL;
     677                 :            : 
     678                 :          0 :         return 0;
     679                 :            : }
     680                 :            : 
     681                 :          0 : int config_parse_routing_policy_rule_priority(
     682                 :            :                 const char *unit,
     683                 :            :                 const char *filename,
     684                 :            :                 unsigned line,
     685                 :            :                 const char *section,
     686                 :            :                 unsigned section_line,
     687                 :            :                 const char *lvalue,
     688                 :            :                 int ltype,
     689                 :            :                 const char *rvalue,
     690                 :            :                 void *data,
     691                 :            :                 void *userdata) {
     692                 :            : 
     693                 :          0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     694                 :          0 :         Network *network = userdata;
     695                 :            :         int r;
     696                 :            : 
     697         [ #  # ]:          0 :         assert(filename);
     698         [ #  # ]:          0 :         assert(section);
     699         [ #  # ]:          0 :         assert(lvalue);
     700         [ #  # ]:          0 :         assert(rvalue);
     701         [ #  # ]:          0 :         assert(data);
     702                 :            : 
     703                 :          0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     704         [ #  # ]:          0 :         if (r < 0)
     705                 :          0 :                 return r;
     706                 :            : 
     707                 :          0 :         r = safe_atou32(rvalue, &n->priority);
     708         [ #  # ]:          0 :         if (r < 0) {
     709         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
     710                 :          0 :                 return 0;
     711                 :            :         }
     712                 :            : 
     713                 :          0 :         n = NULL;
     714                 :            : 
     715                 :          0 :         return 0;
     716                 :            : }
     717                 :            : 
     718                 :          0 : int config_parse_routing_policy_rule_table(
     719                 :            :                 const char *unit,
     720                 :            :                 const char *filename,
     721                 :            :                 unsigned line,
     722                 :            :                 const char *section,
     723                 :            :                 unsigned section_line,
     724                 :            :                 const char *lvalue,
     725                 :            :                 int ltype,
     726                 :            :                 const char *rvalue,
     727                 :            :                 void *data,
     728                 :            :                 void *userdata) {
     729                 :            : 
     730                 :          0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     731                 :          0 :         Network *network = userdata;
     732                 :            :         int r;
     733                 :            : 
     734         [ #  # ]:          0 :         assert(filename);
     735         [ #  # ]:          0 :         assert(section);
     736         [ #  # ]:          0 :         assert(lvalue);
     737         [ #  # ]:          0 :         assert(rvalue);
     738         [ #  # ]:          0 :         assert(data);
     739                 :            : 
     740                 :          0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     741         [ #  # ]:          0 :         if (r < 0)
     742                 :          0 :                 return r;
     743                 :            : 
     744                 :          0 :         r = safe_atou32(rvalue, &n->table);
     745         [ #  # ]:          0 :         if (r < 0) {
     746         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
     747                 :          0 :                 return 0;
     748                 :            :         }
     749                 :            : 
     750                 :          0 :         n = NULL;
     751                 :            : 
     752                 :          0 :         return 0;
     753                 :            : }
     754                 :            : 
     755                 :          0 : int config_parse_routing_policy_rule_fwmark_mask(
     756                 :            :                 const char *unit,
     757                 :            :                 const char *filename,
     758                 :            :                 unsigned line,
     759                 :            :                 const char *section,
     760                 :            :                 unsigned section_line,
     761                 :            :                 const char *lvalue,
     762                 :            :                 int ltype,
     763                 :            :                 const char *rvalue,
     764                 :            :                 void *data,
     765                 :            :                 void *userdata) {
     766                 :            : 
     767                 :          0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     768                 :          0 :         Network *network = userdata;
     769                 :            :         int r;
     770                 :            : 
     771         [ #  # ]:          0 :         assert(filename);
     772         [ #  # ]:          0 :         assert(section);
     773         [ #  # ]:          0 :         assert(lvalue);
     774         [ #  # ]:          0 :         assert(rvalue);
     775         [ #  # ]:          0 :         assert(data);
     776                 :            : 
     777                 :          0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     778         [ #  # ]:          0 :         if (r < 0)
     779                 :          0 :                 return r;
     780                 :            : 
     781                 :          0 :         r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
     782         [ #  # ]:          0 :         if (r < 0) {
     783         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
     784                 :          0 :                 return 0;
     785                 :            :         }
     786                 :            : 
     787                 :          0 :         n = NULL;
     788                 :            : 
     789                 :          0 :         return 0;
     790                 :            : }
     791                 :            : 
     792                 :          0 : int config_parse_routing_policy_rule_prefix(
     793                 :            :                 const char *unit,
     794                 :            :                 const char *filename,
     795                 :            :                 unsigned line,
     796                 :            :                 const char *section,
     797                 :            :                 unsigned section_line,
     798                 :            :                 const char *lvalue,
     799                 :            :                 int ltype,
     800                 :            :                 const char *rvalue,
     801                 :            :                 void *data,
     802                 :            :                 void *userdata) {
     803                 :            : 
     804                 :          0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     805                 :          0 :         Network *network = userdata;
     806                 :            :         union in_addr_union *buffer;
     807                 :            :         uint8_t *prefixlen;
     808                 :            :         int r;
     809                 :            : 
     810         [ #  # ]:          0 :         assert(filename);
     811         [ #  # ]:          0 :         assert(section);
     812         [ #  # ]:          0 :         assert(lvalue);
     813         [ #  # ]:          0 :         assert(rvalue);
     814         [ #  # ]:          0 :         assert(data);
     815                 :            : 
     816                 :          0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     817         [ #  # ]:          0 :         if (r < 0)
     818                 :          0 :                 return r;
     819                 :            : 
     820         [ #  # ]:          0 :         if (streq(lvalue, "To")) {
     821                 :          0 :                 buffer = &n->to;
     822                 :          0 :                 prefixlen = &n->to_prefixlen;
     823                 :            :         } else {
     824                 :          0 :                 buffer = &n->from;
     825                 :          0 :                 prefixlen = &n->from_prefixlen;
     826                 :            :         }
     827                 :            : 
     828         [ #  # ]:          0 :         if (n->family == AF_UNSPEC)
     829                 :          0 :                 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
     830                 :            :         else
     831                 :          0 :                 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
     832         [ #  # ]:          0 :         if (r < 0) {
     833         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
     834                 :          0 :                 return 0;
     835                 :            :         }
     836                 :            : 
     837                 :          0 :         n = NULL;
     838                 :            : 
     839                 :          0 :         return 0;
     840                 :            : }
     841                 :            : 
     842                 :          0 : int config_parse_routing_policy_rule_device(
     843                 :            :                 const char *unit,
     844                 :            :                 const char *filename,
     845                 :            :                 unsigned line,
     846                 :            :                 const char *section,
     847                 :            :                 unsigned section_line,
     848                 :            :                 const char *lvalue,
     849                 :            :                 int ltype,
     850                 :            :                 const char *rvalue,
     851                 :            :                 void *data,
     852                 :            :                 void *userdata) {
     853                 :            : 
     854                 :          0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     855                 :          0 :         Network *network = userdata;
     856                 :            :         int r;
     857                 :            : 
     858         [ #  # ]:          0 :         assert(filename);
     859         [ #  # ]:          0 :         assert(section);
     860         [ #  # ]:          0 :         assert(lvalue);
     861         [ #  # ]:          0 :         assert(rvalue);
     862         [ #  # ]:          0 :         assert(data);
     863                 :            : 
     864                 :          0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     865         [ #  # ]:          0 :         if (r < 0)
     866                 :          0 :                 return r;
     867                 :            : 
     868         [ #  # ]:          0 :         if (!ifname_valid(rvalue)) {
     869         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
     870                 :          0 :                 return 0;
     871                 :            :         }
     872                 :            : 
     873         [ #  # ]:          0 :         if (streq(lvalue, "IncomingInterface")) {
     874                 :          0 :                 r = free_and_strdup(&n->iif, rvalue);
     875         [ #  # ]:          0 :                 if (r < 0)
     876                 :          0 :                         return log_oom();
     877                 :            :         } else {
     878                 :          0 :                 r = free_and_strdup(&n->oif, rvalue);
     879         [ #  # ]:          0 :                 if (r < 0)
     880                 :          0 :                         return log_oom();
     881                 :            :         }
     882                 :            : 
     883                 :          0 :         n = NULL;
     884                 :            : 
     885                 :          0 :         return 0;
     886                 :            : }
     887                 :            : 
     888                 :          0 : int config_parse_routing_policy_rule_port_range(
     889                 :            :                 const char *unit,
     890                 :            :                 const char *filename,
     891                 :            :                 unsigned line,
     892                 :            :                 const char *section,
     893                 :            :                 unsigned section_line,
     894                 :            :                 const char *lvalue,
     895                 :            :                 int ltype,
     896                 :            :                 const char *rvalue,
     897                 :            :                 void *data,
     898                 :            :                 void *userdata) {
     899                 :          0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     900                 :          0 :         Network *network = userdata;
     901                 :            :         uint16_t low, high;
     902                 :            :         int r;
     903                 :            : 
     904         [ #  # ]:          0 :         assert(filename);
     905         [ #  # ]:          0 :         assert(section);
     906         [ #  # ]:          0 :         assert(lvalue);
     907         [ #  # ]:          0 :         assert(rvalue);
     908         [ #  # ]:          0 :         assert(data);
     909                 :            : 
     910                 :          0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     911         [ #  # ]:          0 :         if (r < 0)
     912                 :          0 :                 return r;
     913                 :            : 
     914                 :          0 :         r = parse_ip_port_range(rvalue, &low, &high);
     915         [ #  # ]:          0 :         if (r < 0) {
     916         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
     917                 :          0 :                 return 0;
     918                 :            :         }
     919                 :            : 
     920         [ #  # ]:          0 :         if (streq(lvalue, "SourcePort")) {
     921                 :          0 :                 n->sport.start = low;
     922                 :          0 :                 n->sport.end = high;
     923                 :            :         } else {
     924                 :          0 :                 n->dport.start = low;
     925                 :          0 :                 n->dport.end = high;
     926                 :            :         }
     927                 :            : 
     928                 :          0 :         n = NULL;
     929                 :            : 
     930                 :          0 :         return 0;
     931                 :            : }
     932                 :            : 
     933                 :          0 : int config_parse_routing_policy_rule_ip_protocol(
     934                 :            :                 const char *unit,
     935                 :            :                 const char *filename,
     936                 :            :                 unsigned line,
     937                 :            :                 const char *section,
     938                 :            :                 unsigned section_line,
     939                 :            :                 const char *lvalue,
     940                 :            :                 int ltype,
     941                 :            :                 const char *rvalue,
     942                 :            :                 void *data,
     943                 :            :                 void *userdata) {
     944                 :            : 
     945                 :          0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     946                 :          0 :         Network *network = userdata;
     947                 :            :         int r;
     948                 :            : 
     949         [ #  # ]:          0 :         assert(filename);
     950         [ #  # ]:          0 :         assert(section);
     951         [ #  # ]:          0 :         assert(lvalue);
     952         [ #  # ]:          0 :         assert(rvalue);
     953         [ #  # ]:          0 :         assert(data);
     954                 :            : 
     955                 :          0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     956         [ #  # ]:          0 :         if (r < 0)
     957                 :          0 :                 return r;
     958                 :            : 
     959                 :          0 :         r = parse_ip_protocol(rvalue);
     960         [ #  # ]:          0 :         if (r < 0) {
     961         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
     962                 :          0 :                 return 0;
     963                 :            :         }
     964                 :            : 
     965                 :          0 :         n->protocol = r;
     966                 :            : 
     967                 :          0 :         n = NULL;
     968                 :            : 
     969                 :          0 :         return 0;
     970                 :            : }
     971                 :            : 
     972                 :          0 : int config_parse_routing_policy_rule_invert(
     973                 :            :                 const char *unit,
     974                 :            :                 const char *filename,
     975                 :            :                 unsigned line,
     976                 :            :                 const char *section,
     977                 :            :                 unsigned section_line,
     978                 :            :                 const char *lvalue,
     979                 :            :                 int ltype,
     980                 :            :                 const char *rvalue,
     981                 :            :                 void *data,
     982                 :            :                 void *userdata) {
     983                 :            : 
     984                 :          0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
     985                 :          0 :         Network *network = userdata;
     986                 :            :         int r;
     987                 :            : 
     988         [ #  # ]:          0 :         assert(filename);
     989         [ #  # ]:          0 :         assert(section);
     990         [ #  # ]:          0 :         assert(lvalue);
     991         [ #  # ]:          0 :         assert(rvalue);
     992         [ #  # ]:          0 :         assert(data);
     993                 :            : 
     994                 :          0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
     995         [ #  # ]:          0 :         if (r < 0)
     996                 :          0 :                 return r;
     997                 :            : 
     998                 :          0 :         r = parse_boolean(rvalue);
     999         [ #  # ]:          0 :         if (r < 0) {
    1000         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
    1001                 :          0 :                 return 0;
    1002                 :            :         }
    1003                 :            : 
    1004                 :          0 :         n->invert_rule = r;
    1005                 :            : 
    1006                 :          0 :         n = NULL;
    1007                 :            : 
    1008                 :          0 :         return 0;
    1009                 :            : }
    1010                 :            : 
    1011                 :          0 : int config_parse_routing_policy_rule_family(
    1012                 :            :                 const char *unit,
    1013                 :            :                 const char *filename,
    1014                 :            :                 unsigned line,
    1015                 :            :                 const char *section,
    1016                 :            :                 unsigned section_line,
    1017                 :            :                 const char *lvalue,
    1018                 :            :                 int ltype,
    1019                 :            :                 const char *rvalue,
    1020                 :            :                 void *data,
    1021                 :            :                 void *userdata) {
    1022                 :            : 
    1023                 :          0 :         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
    1024                 :          0 :         Network *network = userdata;
    1025                 :            :         AddressFamily a;
    1026                 :            :         int r;
    1027                 :            : 
    1028         [ #  # ]:          0 :         assert(filename);
    1029         [ #  # ]:          0 :         assert(section);
    1030         [ #  # ]:          0 :         assert(lvalue);
    1031         [ #  # ]:          0 :         assert(rvalue);
    1032         [ #  # ]:          0 :         assert(data);
    1033                 :            : 
    1034                 :          0 :         r = routing_policy_rule_new_static(network, filename, section_line, &n);
    1035         [ #  # ]:          0 :         if (r < 0)
    1036                 :          0 :                 return r;
    1037                 :            : 
    1038                 :          0 :         a = routing_policy_rule_address_family_from_string(rvalue);
    1039         [ #  # ]:          0 :         if (a < 0) {
    1040         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, 0,
    1041                 :            :                            "Invalid address family '%s', ignoring.", rvalue);
    1042                 :          0 :                 return 0;
    1043                 :            :         }
    1044                 :            : 
    1045                 :          0 :         n->address_family = a;
    1046                 :          0 :         n = NULL;
    1047                 :            : 
    1048                 :          0 :         return 0;
    1049                 :            : }
    1050                 :            : 
    1051                 :         32 : static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
    1052                 :         32 :         _cleanup_free_ char *s = NULL;
    1053                 :            :         size_t size;
    1054                 :            :         int r;
    1055                 :            : 
    1056         [ -  + ]:         32 :         assert(state_file);
    1057                 :            : 
    1058                 :         32 :         r = read_full_file(state_file, &s, &size);
    1059         [ +  + ]:         32 :         if (r == -ENOENT)
    1060                 :          4 :                 return -ENODATA;
    1061         [ -  + ]:         28 :         if (r < 0)
    1062                 :          0 :                 return r;
    1063         [ -  + ]:         28 :         if (size <= 0)
    1064                 :          0 :                 return -ENODATA;
    1065                 :            : 
    1066                 :         28 :         *ret = TAKE_PTR(s);
    1067                 :            : 
    1068                 :         28 :         return size;
    1069                 :            : }
    1070                 :            : 
    1071                 :         28 : int routing_policy_serialize_rules(Set *rules, FILE *f) {
    1072                 :         28 :         RoutingPolicyRule *rule = NULL;
    1073                 :            :         Iterator i;
    1074                 :            :         int r;
    1075                 :            : 
    1076         [ -  + ]:         28 :         assert(f);
    1077                 :            : 
    1078         [ +  + ]:         56 :         SET_FOREACH(rule, rules, i) {
    1079   [ +  -  +  - ]:         28 :                 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
    1080                 :         28 :                 bool space = false;
    1081                 :            :                 const char *family_str;
    1082                 :            : 
    1083                 :         28 :                 fputs("RULE=", f);
    1084                 :            : 
    1085         [ +  - ]:         28 :                 if (!in_addr_is_null(rule->family, &rule->from)) {
    1086                 :         28 :                         r = in_addr_to_string(rule->family, &rule->from, &from_str);
    1087         [ -  + ]:         28 :                         if (r < 0)
    1088                 :          0 :                                 return r;
    1089                 :            : 
    1090                 :         28 :                         fprintf(f, "from=%s/%hhu",
    1091                 :         28 :                                 from_str, rule->from_prefixlen);
    1092                 :         28 :                         space = true;
    1093                 :            :                 }
    1094                 :            : 
    1095         [ +  - ]:         28 :                 if (!in_addr_is_null(rule->family, &rule->to)) {
    1096                 :         28 :                         r = in_addr_to_string(rule->family, &rule->to, &to_str);
    1097         [ -  + ]:         28 :                         if (r < 0)
    1098                 :          0 :                                 return r;
    1099                 :            : 
    1100                 :         28 :                         fprintf(f, "%sto=%s/%hhu",
    1101                 :            :                                 space ? " " : "",
    1102         [ +  - ]:         28 :                                 to_str, rule->to_prefixlen);
    1103                 :         28 :                         space = true;
    1104                 :            :                 }
    1105                 :            : 
    1106                 :         28 :                 family_str = af_to_name(rule->family);
    1107         [ +  - ]:         28 :                 if (family_str)
    1108         [ +  - ]:         28 :                 fprintf(f, "%sfamily=%s",
    1109                 :            :                         space ? " " : "",
    1110                 :            :                         family_str);
    1111                 :            : 
    1112         [ +  + ]:         28 :                 if (rule->tos != 0) {
    1113                 :          8 :                         fprintf(f, "%stos=%hhu",
    1114                 :            :                                 space ? " " : "",
    1115         [ +  - ]:          8 :                                 rule->tos);
    1116                 :          8 :                         space = true;
    1117                 :            :                 }
    1118                 :            : 
    1119                 :         28 :                 fprintf(f, "%spriority=%"PRIu32,
    1120                 :            :                         space ? " " : "",
    1121         [ +  - ]:         28 :                         rule->priority);
    1122                 :            : 
    1123         [ +  + ]:         28 :                 if (rule->fwmark != 0) {
    1124                 :          8 :                         fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
    1125                 :            :                                 space ? " " : "",
    1126         [ +  - ]:          8 :                                 rule->fwmark, rule->fwmask);
    1127                 :          8 :                         space = true;
    1128                 :            :                 }
    1129                 :            : 
    1130         [ +  + ]:         28 :                 if (rule->iif) {
    1131                 :          8 :                         fprintf(f, "%siif=%s",
    1132                 :            :                                 space ? " " : "",
    1133         [ +  - ]:          8 :                                 rule->iif);
    1134                 :          8 :                         space = true;
    1135                 :            :                 }
    1136                 :            : 
    1137         [ +  + ]:         28 :                 if (rule->oif) {
    1138                 :          8 :                         fprintf(f, "%soif=%s",
    1139                 :            :                                 space ? " " : "",
    1140         [ +  - ]:          8 :                                 rule->oif);
    1141                 :          8 :                         space = true;
    1142                 :            :                 }
    1143                 :            : 
    1144         [ -  + ]:         28 :                 if (rule->protocol != 0) {
    1145                 :          0 :                         fprintf(f, "%sprotocol=%hhu",
    1146                 :            :                                 space ? " " : "",
    1147         [ #  # ]:          0 :                                 rule->protocol);
    1148                 :          0 :                         space = true;
    1149                 :            :                 }
    1150                 :            : 
    1151   [ +  -  -  + ]:         28 :                 if (rule->sport.start != 0 || rule->sport.end != 0) {
    1152                 :          0 :                         fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
    1153                 :            :                                 space ? " " : "",
    1154         [ #  # ]:          0 :                                 rule->sport.start, rule->sport.end);
    1155                 :          0 :                         space = true;
    1156                 :            :                 }
    1157                 :            : 
    1158   [ +  -  -  + ]:         28 :                 if (rule->dport.start != 0 || rule->dport.end != 0) {
    1159                 :          0 :                         fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
    1160                 :            :                                 space ? " " : "",
    1161         [ #  # ]:          0 :                                 rule->dport.start, rule->dport.end);
    1162                 :          0 :                         space = true;
    1163                 :            :                 }
    1164                 :            : 
    1165                 :         28 :                 fprintf(f, "%stable=%"PRIu32 "\n",
    1166                 :            :                         space ? " " : "",
    1167         [ +  - ]:         28 :                         rule->table);
    1168                 :            :         }
    1169                 :            : 
    1170                 :         28 :         return 0;
    1171                 :            : }
    1172                 :            : 
    1173                 :         32 : int routing_policy_load_rules(const char *state_file, Set **rules) {
    1174                 :         32 :         _cleanup_strv_free_ char **l = NULL;
    1175                 :         32 :         _cleanup_free_ char *data = NULL;
    1176                 :         32 :         uint16_t low = 0, high = 0;
    1177                 :            :         const char *p;
    1178                 :            :         char **i;
    1179                 :            :         int r;
    1180                 :            : 
    1181         [ -  + ]:         32 :         assert(state_file);
    1182         [ -  + ]:         32 :         assert(rules);
    1183                 :            : 
    1184                 :         32 :         r = routing_policy_rule_read_full_file(state_file, &data);
    1185         [ +  + ]:         32 :         if (r <= 0)
    1186                 :          4 :                 return r;
    1187                 :            : 
    1188                 :         28 :         l = strv_split_newlines(data);
    1189         [ -  + ]:         28 :         if (!l)
    1190                 :          0 :                 return -ENOMEM;
    1191                 :            : 
    1192                 :         28 :         r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
    1193         [ -  + ]:         28 :         if (r < 0)
    1194                 :          0 :                 return r;
    1195                 :            : 
    1196   [ +  -  +  + ]:         56 :         STRV_FOREACH(i, l) {
    1197      [ +  -  - ]:         28 :                 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
    1198                 :            : 
    1199                 :         28 :                 p = startswith(*i, "RULE=");
    1200         [ -  + ]:         28 :                 if (!p)
    1201                 :          0 :                         continue;
    1202                 :            : 
    1203                 :         28 :                 r = routing_policy_rule_new(&rule);
    1204         [ -  + ]:         28 :                 if (r < 0)
    1205                 :          0 :                         return r;
    1206                 :            : 
    1207                 :        168 :                 for (;;) {
    1208   [ +  -  +  -  :        252 :                         _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
          +  -  +  -  +  
                -  +  - ]
    1209                 :            : 
    1210                 :        196 :                         r = extract_first_word(&p, &word, NULL, 0);
    1211         [ -  + ]:        196 :                         if (r < 0)
    1212                 :          0 :                                 return r;
    1213         [ +  + ]:        196 :                         if (r == 0)
    1214                 :         28 :                                 break;
    1215                 :            : 
    1216                 :        168 :                         r = split_pair(word, "=", &a, &b);
    1217         [ -  + ]:        168 :                         if (r < 0)
    1218                 :          0 :                                 continue;
    1219                 :            : 
    1220         [ +  + ]:        168 :                         if (STR_IN_SET(a, "from", "to")) {
    1221                 :            :                                 union in_addr_union *buffer;
    1222                 :            :                                 uint8_t *prefixlen;
    1223                 :            : 
    1224         [ +  + ]:         64 :                                 if (streq(a, "to")) {
    1225                 :         32 :                                         buffer = &rule->to;
    1226                 :         32 :                                         prefixlen = &rule->to_prefixlen;
    1227                 :            :                                 } else {
    1228                 :         32 :                                         buffer = &rule->from;
    1229                 :         32 :                                         prefixlen = &rule->from_prefixlen;
    1230                 :            :                                 }
    1231                 :            : 
    1232                 :         64 :                                 r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
    1233         [ -  + ]:         64 :                                 if (r < 0) {
    1234         [ #  # ]:          0 :                                         log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
    1235                 :          0 :                                         continue;
    1236                 :            :                                 }
    1237                 :            : 
    1238         [ +  + ]:        104 :                         } else if (streq(a, "family")) {
    1239                 :         16 :                                 r = af_from_name(b);
    1240         [ -  + ]:         16 :                                 if (r < 0) {
    1241         [ #  # ]:          0 :                                         log_error_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b);
    1242                 :          0 :                                         continue;
    1243                 :            :                                 }
    1244                 :         16 :                                 rule->family = r;
    1245         [ +  + ]:         88 :                         } else if (streq(a, "tos")) {
    1246                 :          8 :                                 r = safe_atou8(b, &rule->tos);
    1247         [ -  + ]:          8 :                                 if (r < 0) {
    1248         [ #  # ]:          0 :                                         log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
    1249                 :          0 :                                         continue;
    1250                 :            :                                 }
    1251         [ +  + ]:         80 :                         } else if (streq(a, "table")) {
    1252                 :         28 :                                 r = safe_atou32(b, &rule->table);
    1253         [ -  + ]:         28 :                                 if (r < 0) {
    1254         [ #  # ]:          0 :                                         log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
    1255                 :          0 :                                         continue;
    1256                 :            :                                 }
    1257         [ +  + ]:         52 :                         } else if (streq(a, "priority")) {
    1258                 :         12 :                                 r = safe_atou32(b, &rule->priority);
    1259         [ -  + ]:         12 :                                 if (r < 0) {
    1260         [ #  # ]:          0 :                                         log_error_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b);
    1261                 :          0 :                                         continue;
    1262                 :            :                                 }
    1263         [ +  + ]:         40 :                         } else if (streq(a, "fwmark")) {
    1264                 :            : 
    1265                 :         12 :                                 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
    1266         [ -  + ]:         12 :                                 if (r < 0) {
    1267         [ #  # ]:          0 :                                         log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
    1268                 :          0 :                                         continue;
    1269                 :            :                                 }
    1270         [ +  + ]:         28 :                         } else if (streq(a, "iif")) {
    1271                 :            : 
    1272         [ -  + ]:         12 :                                 if (free_and_strdup(&rule->iif, b) < 0)
    1273                 :          0 :                                         return log_oom();
    1274                 :            : 
    1275         [ +  + ]:         16 :                         } else if (streq(a, "oif")) {
    1276                 :            : 
    1277         [ -  + ]:         12 :                                 if (free_and_strdup(&rule->oif, b) < 0)
    1278                 :          0 :                                         return log_oom();
    1279         [ -  + ]:          4 :                         } else if (streq(a, "protocol")) {
    1280                 :          0 :                                 r = safe_atou8(b, &rule->protocol);
    1281         [ #  # ]:          0 :                                 if (r < 0) {
    1282         [ #  # ]:          0 :                                         log_error_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
    1283                 :          0 :                                         continue;
    1284                 :            :                                 }
    1285         [ -  + ]:          4 :                         } else if (streq(a, "sourceport")) {
    1286                 :            : 
    1287                 :          0 :                                 r = parse_ip_port_range(b, &low, &high);
    1288         [ #  # ]:          0 :                                 if (r < 0) {
    1289         [ #  # ]:          0 :                                         log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment:'%s'", b);
    1290                 :          0 :                                         continue;
    1291                 :            :                                 }
    1292                 :            : 
    1293                 :          0 :                                 rule->sport.start = low;
    1294                 :          0 :                                 rule->sport.end = high;
    1295                 :            : 
    1296         [ -  + ]:          4 :                         } else if (streq(a, "destinationport")) {
    1297                 :            : 
    1298                 :          0 :                                 r = parse_ip_port_range(b, &low, &high);
    1299         [ #  # ]:          0 :                                 if (r < 0) {
    1300         [ #  # ]:          0 :                                         log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment:'%s'", b);
    1301                 :          0 :                                         continue;
    1302                 :            :                                 }
    1303                 :            : 
    1304                 :          0 :                                 rule->dport.start = low;
    1305                 :          0 :                                 rule->dport.end = high;
    1306                 :            :                         }
    1307                 :            :                 }
    1308                 :            : 
    1309                 :         28 :                 r = set_put(*rules, rule);
    1310         [ -  + ]:         28 :                 if (r < 0) {
    1311         [ #  # ]:          0 :                         log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
    1312                 :          0 :                         continue;
    1313                 :            :                 }
    1314         [ +  - ]:         28 :                 if (r > 0)
    1315                 :         28 :                         rule = NULL;
    1316                 :            :         }
    1317                 :            : 
    1318                 :         28 :         return 0;
    1319                 :            : }
    1320                 :            : 
    1321                 :          0 : static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
    1322                 :            :         RoutingPolicyRule *link_rule;
    1323                 :            :         Iterator i;
    1324                 :            :         Link *link;
    1325                 :            : 
    1326         [ #  # ]:          0 :         assert(m);
    1327         [ #  # ]:          0 :         assert(rule);
    1328                 :            : 
    1329         [ #  # ]:          0 :         HASHMAP_FOREACH(link, m->links, i) {
    1330         [ #  # ]:          0 :                 if (!link->network)
    1331                 :          0 :                         continue;
    1332                 :            : 
    1333         [ #  # ]:          0 :                 LIST_FOREACH(rules, link_rule, link->network->rules)
    1334         [ #  # ]:          0 :                         if (routing_policy_rule_compare_func(link_rule, rule) == 0)
    1335                 :          0 :                                 return true;
    1336                 :            :         }
    1337                 :            : 
    1338                 :          0 :         return false;
    1339                 :            : }
    1340                 :            : 
    1341                 :          0 : void routing_policy_rule_purge(Manager *m, Link *link) {
    1342                 :            :         RoutingPolicyRule *rule, *existing;
    1343                 :            :         Iterator i;
    1344                 :            :         int r;
    1345                 :            : 
    1346         [ #  # ]:          0 :         assert(m);
    1347         [ #  # ]:          0 :         assert(link);
    1348                 :            : 
    1349         [ #  # ]:          0 :         SET_FOREACH(rule, m->rules_saved, i) {
    1350                 :          0 :                 existing = set_get(m->rules_foreign, rule);
    1351         [ #  # ]:          0 :                 if (!existing)
    1352                 :          0 :                         continue; /* Saved rule does not exist anymore. */
    1353                 :            : 
    1354         [ #  # ]:          0 :                 if (manager_links_have_routing_policy_rule(m, existing))
    1355                 :          0 :                         continue; /* Existing links have the saved rule. */
    1356                 :            : 
    1357                 :            :                 /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
    1358                 :            :                  * later when it is requested. */
    1359                 :            : 
    1360                 :          0 :                 r = routing_policy_rule_remove(existing, link, NULL);
    1361         [ #  # ]:          0 :                 if (r < 0) {
    1362         [ #  # ]:          0 :                         log_warning_errno(r, "Could not remove routing policy rules: %m");
    1363                 :          0 :                         continue;
    1364                 :            :                 }
    1365                 :            : 
    1366                 :          0 :                 link->routing_policy_rule_remove_messages++;
    1367                 :            : 
    1368         [ #  # ]:          0 :                 assert_se(set_remove(m->rules_foreign, existing) == existing);
    1369                 :          0 :                 routing_policy_rule_free(existing);
    1370                 :            :         }
    1371                 :          0 : }

Generated by: LCOV version 1.14