Index: bgpd/Makefile =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/Makefile,v retrieving revision 1.36 diff -u -p -r1.36 Makefile --- bgpd/Makefile 1 Jan 2020 07:25:04 -0000 1.36 +++ bgpd/Makefile 21 Apr 2021 05:10:03 -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.233 diff -u -p -r1.233 bgpd.c --- bgpd/bgpd.c 4 Jan 2021 17:44:14 -0000 1.233 +++ bgpd/bgpd.c 21 Apr 2021 05:10:03 -0000 @@ -330,6 +330,13 @@ BROKEN if (pledge("stdio rpath wpath cpa } } + if (reconfpending == 0) { + if (kr_ifchanged()) { + log_info("interfaces changed"); + reconfig = 1; + } + } + if (reconfig) { u_int error; @@ -513,6 +520,14 @@ send_config(struct bgpd_config *conf) reconfpending = 2; /* one per child */ expand_networks(conf); + 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); + } cflags = conf->flags; Index: bgpd/bgpd.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v retrieving revision 1.409 diff -u -p -r1.409 bgpd.h --- bgpd/bgpd.h 4 Jan 2021 13:40:32 -0000 1.409 +++ bgpd/bgpd.h 21 Apr 2021 05:10:03 -0000 @@ -676,7 +676,9 @@ struct kif { u_int8_t if_type; u_int8_t link_state; u_int8_t nh_reachable; /* for nexthop verification */ - u_int8_t depend_state; /* for session depend on */ + u_int8_t depend_state; /* for session/filter depend on */ + u_int8_t filter_depend; /* for filter depend on rules */ + u_int8_t state_changed; }; struct session_up { @@ -817,6 +819,12 @@ struct filter_ovs { u_int8_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 @@ -998,6 +1006,7 @@ struct filter_match { struct filter_prefixset prefixset; struct filter_originset originset; struct filter_ovs ovs; + struct filter_depend_on depend_on; }; struct filter_rule { @@ -1245,6 +1254,9 @@ void kr_nexthop_delete(u_int32_t, stru struct bgpd_config *); 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, u_int64_t, struct network_head *); int kr_reload(void); struct in6_addr *prefixlen2mask6(u_int8_t prefixlen); Index: bgpd/kroute.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v retrieving revision 1.240 diff -u -p -r1.240 kroute.c --- bgpd/kroute.c 29 Dec 2020 09:20:25 -0000 1.240 +++ bgpd/kroute.c 21 Apr 2021 05:10:03 -0000 @@ -1248,6 +1248,48 @@ kr_ifinfo(char *ifname) } } +int +kr_ifchanged(void) +{ + struct kif_node *kif; + int changed = 0; + + RB_FOREACH(kif, kif_tree, &kit) { + if (kif->k.state_changed) { + log_info("depended-on interface %s changed state", + kif->k.ifname); + changed = 1; + kif->k.state_changed = 0; + } + } + + return changed; +} + +int +kr_ifdepend(const char *ifname) +{ + struct kif_node *kif; + + RB_FOREACH(kif, kif_tree, &kit) { + if (!strcmp(ifname, kif->k.ifname)) { + kif->k.filter_depend = 1; + return kif->k.depend_state; + } + } + + return 0; +} + +void +kr_ifdepend_reset(void) +{ + struct kif_node *kif; + + RB_FOREACH(kif, kif_tree, &kit) + kif->k.filter_depend = 0; +} + void kr_net_delete(struct network *n) { @@ -2824,6 +2866,8 @@ if_change(u_short ifindex, int flags, st kif->k.rdomain = ifd->ifi_rdomain; kif->k.baudrate = ifd->ifi_baudrate; kif->k.depend_state = kif_depend_state(&kif->k); + if (kif->k.filter_depend) + kif->k.state_changed = 1; send_imsg_session(IMSG_IFINFO, 0, &kif->k, sizeof(kif->k)); @@ -2874,6 +2918,7 @@ if_announce(void *msg, u_int rdomain) } kif->k.ifindex = ifan->ifan_index; + kif->k.state_changed = 1; strlcpy(kif->k.ifname, ifan->ifan_name, sizeof(kif->k.ifname)); kif_insert(kif); break; Index: bgpd/parse.y =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v retrieving revision 1.411 diff -u -p -r1.411 parse.y --- bgpd/parse.y 29 Dec 2020 15:30:34 -0000 1.411 +++ bgpd/parse.y 21 Apr 2021 05:10:03 -0000 @@ -201,7 +201,7 @@ typedef struct { %token EBGP IBGP %token LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART %token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY -%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 @@ -229,7 +229,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 @@ -2265,6 +2265,19 @@ filter_elm : filter_prefix_h { fmopts.m.ovs.validity = $2; fmopts.m.ovs.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 */ { bzero(&$$, sizeof($$)); } @@ -2383,6 +2396,11 @@ delete : /* empty */ { $$ = 0; } | DELETE { $$ = 1; } ; +dependstate : /* empty */ { $$ = 1; } + | UP { $$ = 1; } + | DOWN { $$ = 0; } + ; + filter_set_opt : LOCALPREF NUMBER { if ($2 < -INT_MAX || $2 > UINT_MAX) { yyerror("bad localpref %lld", $2); @@ -2887,6 +2905,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.144 diff -u -p -r1.144 printconf.c --- bgpd/printconf.c 29 Dec 2020 15:30:34 -0000 1.144 +++ bgpd/printconf.c 21 Apr 2021 05:10:03 -0000 @@ -829,6 +829,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.126 diff -u -p -r1.126 rde_filter.c --- bgpd/rde_filter.c 30 Dec 2020 07:29:56 -0000 1.126 +++ bgpd/rde_filter.c 21 Apr 2021 05:10:03 -0000 @@ -226,6 +226,10 @@ rde_filter_match(struct filter_rule *f, if (vstate != f->match.ovs.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,