Index: bgpd/Makefile =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/Makefile,v retrieving revision 1.39 diff -u -p -r1.39 Makefile --- bgpd/Makefile 17 Apr 2023 08:02:21 -0000 1.39 +++ bgpd/Makefile 25 Apr 2024 23:40:45 -0000 @@ -15,5 +15,6 @@ YFLAGS= LDADD+= -lutil DPADD+= ${LIBUTIL} MAN= bgpd.8 bgpd.conf.5 +DEBUG=-g .include Index: bgpd/bgpd.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v retrieving revision 1.262 diff -u -p -r1.262 bgpd.c --- bgpd/bgpd.c 9 Jan 2024 13:41:32 -0000 1.262 +++ bgpd/bgpd.c 25 Apr 2024 23:40:45 -0000 @@ -400,6 +400,13 @@ BROKEN if (pledge("stdio rpath wpath cpa } } + if (reconfpending == 0) { + if (kr_ifchanged()) { + log_info("interfaces changed"); + reconfig = 1; + } + } + for (i = PFD_CONNECT_START; i < npfd; i++) if (pfd[i].revents != 0) bgpd_rtr_connect_done(pfd[i].fd, conf); @@ -603,6 +610,15 @@ send_config(struct bgpd_config *conf) reconfpending = 3; /* one per child */ expand_networks(conf, &conf->networks); + kr_ifdepend_reset(); + TAILQ_FOREACH(r, conf->filters, entry) { + const char *iface = r->match.depend_on.iface; + if (iface[0] == '\0') + continue; + + r->match.depend_on.state = kr_ifdepend(iface); + } + SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry) expand_networks(conf, &vpn->net_l); Index: bgpd/bgpd.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v retrieving revision 1.486 diff -u -p -r1.486 bgpd.h --- bgpd/bgpd.h 19 Feb 2024 10:15:35 -0000 1.486 +++ bgpd/bgpd.h 25 Apr 2024 23:40:45 -0000 @@ -942,6 +942,12 @@ struct filter_vs { uint8_t is_set; }; +struct filter_depend_on { + char iface[SET_NAME_LEN]; + int depend_state; + int state; +}; + /* * Communities are encoded depending on their type. The low byte of flags * is the COMMUNITY_TYPE (BASIC, LARGE, EXT). BASIC encoding is just using @@ -1181,6 +1187,7 @@ struct filter_match { struct filter_originset originset; struct filter_vs ovs; struct filter_vs avs; + struct filter_depend_on depend_on; int maxcomm; int maxextcomm; int maxlargecomm; @@ -1442,6 +1449,9 @@ int kr_nexthop_add(uint32_t, struct bg void kr_nexthop_delete(uint32_t, struct bgpd_addr *); void kr_show_route(struct imsg *); void kr_ifinfo(char *); +int kr_ifchanged(void); +int kr_ifdepend(const char *); +void kr_ifdepend_reset(void); void kr_net_reload(u_int, uint64_t, struct network_head *); int kr_reload(void); int get_mpe_config(const char *, u_int *, u_int *); Index: bgpd/kroute.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v retrieving revision 1.309 diff -u -p -r1.309 kroute.c --- bgpd/kroute.c 9 Jan 2024 13:41:32 -0000 1.309 +++ bgpd/kroute.c 25 Apr 2024 23:40:45 -0000 @@ -109,7 +109,9 @@ struct kif { uint8_t if_type; uint8_t link_state; uint8_t nh_reachable; /* for nexthop verification */ - uint8_t depend_state; /* for session depend on */ + uint8_t depend_state; /* for session/filter depend on */ + uint8_t filter_depend; /* for filter depend on rules */ + uint8_t state_changed; }; int ktable_new(u_int, u_int, char *, int); @@ -1055,6 +1057,48 @@ kr_ifinfo(char *ifname) } } +int +kr_ifchanged(void) +{ + struct kif *kif; + int changed = 0; + + RB_FOREACH(kif, kif_tree, &kit) { + if (kif->state_changed) { + log_info("depended-on interface %s changed state", + kif->ifname); + changed = 1; + kif->state_changed = 0; + } + } + + return changed; +} + +int +kr_ifdepend(const char *ifname) +{ + struct kif *kif; + + RB_FOREACH(kif, kif_tree, &kit) { + if (!strcmp(ifname, kif->ifname)) { + kif->filter_depend = 1; + return kif->depend_state; + } + } + + return 0; +} + +void +kr_ifdepend_reset(void) +{ + struct kif *kif; + + RB_FOREACH(kif, kif_tree, &kit) + kif->filter_depend = 0; +} + static int kr_net_redist_add(struct ktable *kt, struct network_config *net, struct filter_set_head *attr, int dynamic) @@ -2584,6 +2628,8 @@ if_change(u_short ifindex, int flags, st kif->rdomain = ifd->ifi_rdomain; kif->baudrate = ifd->ifi_baudrate; kif->depend_state = kif_depend_state(kif); + if (kif->filter_depend) + kif->state_changed = 1; kr_send_dependon(kif); @@ -2615,6 +2661,7 @@ if_announce(void *msg) } kif->ifindex = ifan->ifan_index; + kif->state_changed = 1; strlcpy(kif->ifname, ifan->ifan_name, sizeof(kif->ifname)); kif_insert(kif); break; Index: bgpd/parse.y =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v retrieving revision 1.455 diff -u -p -r1.455 parse.y --- bgpd/parse.y 16 Aug 2023 08:26:35 -0000 1.455 +++ bgpd/parse.y 25 Apr 2024 23:40:45 -0000 @@ -248,7 +248,7 @@ typedef struct { %token LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART %token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY ENHANCED ADDPATH %token SEND RECV PLUS POLICY ROLE -%token DEMOTE ENFORCE NEIGHBORAS ASOVERRIDE REFLECTOR DEPEND DOWN +%token DEMOTE ENFORCE NEIGHBORAS ASOVERRIDE REFLECTOR DEPEND DOWN UP %token DUMP IN OUT SOCKET RESTRICTED %token LOG TRANSPARENT %token TCP MD5SIG PASSWORD KEY TTLSECURITY @@ -280,7 +280,7 @@ typedef struct { %type address %type prefix addrspec %type prefixset_item -%type action quick direction delete community +%type action quick direction delete community dependstate %type filter_rib_h filter_rib_l filter_rib %type filter_peer filter_peer_l filter_peer_h %type filter_match filter_elm filter_match_h @@ -2963,6 +2963,19 @@ filter_elm : filter_prefix_h { fmopts.m.avs.validity = $2; fmopts.m.avs.is_set = 1; } + | DEPEND ON STRING dependstate { + if (strlcpy(fmopts.m.depend_on.iface, $3, + sizeof(fmopts.m.depend_on.iface)) >= + sizeof(fmopts.m.depend_on.iface)) { + yyerror("interface name \"%s\" too long: " + "max %zu", $3, + sizeof(fmopts.m.depend_on.iface) - 1); + free($3); + YYERROR; + } + fmopts.m.depend_on.depend_state = $4; + free($3); + } ; prefixlenop : /* empty */ { memset(&$$, 0, sizeof($$)); } @@ -3081,6 +3094,11 @@ delete : /* empty */ { $$ = 0; } | DELETE { $$ = 1; } ; +dependstate : /* empty */ { $$ = 1; } + | UP { $$ = 1; } + | DOWN { $$ = 0; } + ; + enforce : yesno { $$ = $1; } | ENFORCE { $$ = 2; } ; @@ -3627,6 +3645,7 @@ lookup(char *s) { "transparent-as", TRANSPARENT}, { "ttl-security", TTLSECURITY}, { "unicast", UNICAST}, + { "up", UP}, { "via", VIA}, { "vpn", VPN}, { "weight", WEIGHT} Index: bgpd/printconf.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v retrieving revision 1.169 diff -u -p -r1.169 printconf.c --- bgpd/printconf.c 10 Jan 2024 13:31:09 -0000 1.169 +++ bgpd/printconf.c 25 Apr 2024 23:40:45 -0000 @@ -1056,6 +1056,11 @@ print_rule(struct bgpd_config *conf, str } } + if (r->match.depend_on.iface[0] != '\0') { + printf("depend on %s %s ", r->match.depend_on.iface, + r->match.depend_on.depend_state ? "up" : "down"); + } + if (r->match.prefix.addr.aid != AID_UNSPEC) { printf("prefix "); print_prefix(&r->match.prefix); Index: bgpd/rde_filter.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_filter.c,v retrieving revision 1.136 diff -u -p -r1.136 rde_filter.c --- bgpd/rde_filter.c 9 May 2023 13:11:19 -0000 1.136 +++ bgpd/rde_filter.c 25 Apr 2024 23:40:45 -0000 @@ -231,6 +231,10 @@ rde_filter_match(struct filter_rule *f, if (((state->vstate >> 4) & ASPA_MASK) != f->match.avs.validity) return (0); } + if (f->match.depend_on.iface[0] != '\0') { + if (f->match.depend_on.state != f->match.depend_on.depend_state) + return (0); + } if (asp != NULL && f->match.as.type != AS_UNDEF) { if (aspath_match(asp->aspath, &f->match.as,