diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index f2aac3646c..c7fabb396a 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1052,7 +1052,8 @@ bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval) } int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, - struct bgp_pbr_entry_action *api) + struct bgp_pbr_entry_action *api, + afi_t afi) { if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_RATE) { api->action = ACTION_TRAFFICRATE; @@ -1076,7 +1077,8 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, } else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_VRF) { /* must use external function */ return 0; - } else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_IP_NH) { + } else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_IP_NH && + afi == AFI_IP) { /* see draft-ietf-idr-flowspec-redirect-ip-02 * Q1: how come a ext. community can host ipv6 address * Q2 : from cisco documentation: diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 812bcc46e7..8ae3b44bab 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -222,7 +222,8 @@ extern bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval); struct bgp_pbr_entry_action; extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, - struct bgp_pbr_entry_action *api); + struct bgp_pbr_entry_action *api, + afi_t afi); extern void bgp_compute_aggregate_ecommunity( struct bgp_aggregate *aggregate, diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 4b1d26b2fe..3e3366bf8b 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -325,10 +325,28 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, json_object_array_add(json_paths, json_ecom_path); } - if (attr->nexthop.s_addr != 0 && - display == NLRI_STRING_FORMAT_LARGE) - vty_out(vty, "\tNLRI NH %-16s\n", - inet_ntoa(attr->nexthop)); + if (display == NLRI_STRING_FORMAT_LARGE) { + char local_buff[INET6_ADDRSTRLEN]; + + local_buff[0] = '\0'; + if (p->u.prefix_flowspec.family == AF_INET && + attr->nexthop.s_addr != 0) + inet_ntop(AF_INET, + &attr->nexthop.s_addr, + local_buff, + INET6_ADDRSTRLEN); + else if (p->u.prefix_flowspec.family == AF_INET6 && + attr->mp_nexthop_len != 0 && + attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV4 && + attr->mp_nexthop_len != BGP_ATTR_NHLEN_VPNV4) + inet_ntop(AF_INET6, + &attr->mp_nexthop_global, + local_buff, + INET6_ADDRSTRLEN); + if (local_buff[0] != '\0') + vty_out(vty, "\tNLRI NH %s\n", + local_buff); + } XFREE(MTYPE_ECOMMUNITY_STR, s); } peer_uptime(path->uptime, timebuf, BGP_UPTIME_LEN, 0, NULL); diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 715781143f..9446575611 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -248,6 +248,7 @@ struct bgp_pbr_val_mask { struct bgp_pbr_filter { uint8_t type; vrf_id_t vrf_id; + uint8_t family; struct prefix *src; struct prefix *dst; uint8_t bitmask_iprule; @@ -793,9 +794,10 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, * do not overwrite * draft-ietf-idr-flowspec-redirect */ - if (api_action_redirect_ip) { - if (api_action_redirect_ip->u.zr - .redirect_ip_v4.s_addr + if (api_action_redirect_ip && + p->u.prefix_flowspec.family == AF_INET) { + if (api_action_redirect_ip->u + .zr.redirect_ip_v4.s_addr != INADDR_ANY) continue; if (path->attr->nexthop.s_addr @@ -807,13 +809,42 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, api_action_redirect_ip->u.zr.duplicate = ecom_eval->val[7]; continue; - } else { + } else if (api_action_redirect_ip && + p->u.prefix_flowspec.family == AF_INET6) { + if (memcmp(&api_action_redirect_ip->u + .zr.redirect_ip_v6, + &in6addr_any, + sizeof(struct in6_addr))) + continue; + if (path->attr->mp_nexthop_len == 0 || + path->attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV4 || + path->attr->mp_nexthop_len == + BGP_ATTR_NHLEN_VPNV4) + continue; + memcpy(&api_action_redirect_ip->u + .zr.redirect_ip_v6, + &path->attr->mp_nexthop_global, + sizeof(struct in6_addr)); + api_action_redirect_ip->u.zr.duplicate + = ecom_eval->val[7]; + continue; + } else if (p->u.prefix_flowspec.family == AF_INET) { api_action->action = ACTION_REDIRECT_IP; api_action->u.zr.redirect_ip_v4.s_addr = path->attr->nexthop.s_addr; api_action->u.zr.duplicate = ecom_eval->val[7]; api_action_redirect_ip = api_action; + } else if (p->u.prefix_flowspec.family == AF_INET6) { + api_action->action = ACTION_REDIRECT_IP; + memcpy(&api_action->u + .zr.redirect_ip_v6, + &path->attr->mp_nexthop_global, + sizeof(struct in6_addr)); + api_action->u.zr.duplicate + = ecom_eval->val[7]; + api_action_redirect_ip = api_action; } } else if ((ecom_eval->val[0] == (char)ECOMMUNITY_ENCODE_IP) && @@ -845,7 +876,8 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, (char)ECOMMUNITY_ENCODE_TRANS_EXP) continue; ret = ecommunity_fill_pbr_action(ecom_eval, - api_action); + api_action, + afi); if (ret != 0) continue; if ((api_action->action == ACTION_TRAFFICRATE) && @@ -1181,6 +1213,7 @@ uint32_t bgp_pbr_action_hash_key(const void *arg) pbra = arg; key = jhash_1word(pbra->table_id, 0x4312abde); key = jhash_1word(pbra->fwmark, key); + key = jhash_1word(pbra->afi, key); return key; } @@ -1198,6 +1231,9 @@ bool bgp_pbr_action_hash_equal(const void *arg1, const void *arg2) if (r1->vrf_id != r2->vrf_id) return false; + if (r1->afi != r2->afi) + return false; + if (memcmp(&r1->nh, &r2->nh, sizeof(struct nexthop))) return false; @@ -1515,18 +1551,25 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api) ptr += delta; } break; - case ACTION_REDIRECT_IP: - char local_buff[INET_ADDRSTRLEN]; + case ACTION_REDIRECT_IP: { + char local_buff[INET6_ADDRSTRLEN]; + void *ptr_ip; INCREMENT_DISPLAY(ptr, nb_items, len); - if (inet_ntop(AF_INET, - &api->actions[i].u.zr.redirect_ip_v4, - local_buff, INET_ADDRSTRLEN) != NULL) + if (api->afi == AF_INET) + ptr_ip = &api->actions[i].u.zr.redirect_ip_v4; + else + ptr_ip = &api->actions[i].u.zr.redirect_ip_v6; + if (inet_ntop(afi2family(api->afi), + ptr_ip, local_buff, + INET6_ADDRSTRLEN) != NULL) { delta = snprintf(ptr, len, "@redirect ip nh %s", local_buff); len -= delta; ptr += delta; + } break; + } case ACTION_REDIRECT: { struct vrf *vrf; @@ -1639,7 +1682,7 @@ static void bgp_pbr_flush_entry(struct bgp *bgp, struct bgp_pbr_action *bpa, if (bpa->installed && bpa->table_id != 0) { bgp_send_pbr_rule_action(bpa, NULL, false); bgp_zebra_announce_default(bpa->bgp, &(bpa->nh), - AFI_IP, + bpa->afi, bpa->table_id, false); bpa->installed = false; @@ -1794,12 +1837,12 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit( temp.flags |= MATCH_IP_SRC_SET; prefix_copy(&temp2.src, bpf->src); } else - temp2.src.family = AF_INET; + temp2.src.family = bpf->family; if (bpf->dst) { temp.flags |= MATCH_IP_DST_SET; prefix_copy(&temp2.dst, bpf->dst); } else - temp2.dst.family = AF_INET; + temp2.dst.family = bpf->family; if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) { if (bpf->protocol == IPPROTO_ICMP) temp.flags |= MATCH_ICMP_SET; @@ -2200,6 +2243,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, if (nh) memcpy(&temp3.nh, nh, sizeof(struct nexthop)); temp3.vrf_id = bpf->vrf_id; + temp3.afi = family2afi(bpf->family); bpa = hash_get(bgp->pbr_action_hash, &temp3, bgp_pbr_action_alloc_intern); @@ -2258,7 +2302,8 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, if (!bpa->installed && !bpa->install_in_progress) { bgp_send_pbr_rule_action(bpa, NULL, true); bgp_zebra_announce_default(bgp, nh, - AFI_IP, bpa->table_id, true); + bpa->afi, + bpa->table_id, true); } /* ip rule add */ if (bpr && !bpr->installed) @@ -2377,11 +2422,11 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, if (bpf->src) prefix_copy(&temp2.src, bpf->src); else - temp2.src.family = AF_INET; + temp2.src.family = bpf->family; if (bpf->dst) prefix_copy(&temp2.dst, bpf->dst); else - temp2.dst.family = AF_INET; + temp2.dst.family = bpf->family; temp2.src_port_min = src_port ? src_port->min_port : 0; temp2.dst_port_min = dst_port ? dst_port->min_port : 0; temp2.src_port_max = src_port ? src_port->max_port : 0; @@ -2428,7 +2473,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, if (!bpa->installed && !bpa->install_in_progress) { bgp_send_pbr_rule_action(bpa, NULL, true); bgp_zebra_announce_default(bgp, nh, - AFI_IP, bpa->table_id, true); + bpa->afi, bpa->table_id, true); } /* ipset create */ @@ -2690,6 +2735,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path, bpf.protocol = proto; bpf.src_port = srcp; bpf.dst_port = dstp; + bpf.family = afi2family(api->afi); if (!add) { bgp_pbr_policyroute_remove_from_zebra(bgp, path, &bpf, &bpof); return; @@ -2739,10 +2785,18 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path, */ break; case ACTION_REDIRECT_IP: - nh.type = NEXTHOP_TYPE_IPV4; - nh.gate.ipv4.s_addr = - api->actions[i].u.zr.redirect_ip_v4.s_addr; nh.vrf_id = api->vrf_id; + if (api->afi == AFI_IP) { + nh.type = NEXTHOP_TYPE_IPV4; + nh.gate.ipv4.s_addr = + api->actions[i].u.zr. + redirect_ip_v4.s_addr; + } else { + nh.type = NEXTHOP_TYPE_IPV6; + memcpy(&nh.gate.ipv6, + &api->actions[i].u.zr.redirect_ip_v6, + sizeof(struct in6_addr)); + } bgp_pbr_policyroute_add_to_zebra(bgp, path, &bpf, &bpof, &nh, &rate); /* XXX combination with REDIRECT_VRF diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h index 403300dc03..ff333d2f10 100644 --- a/bgpd/bgp_pbr.h +++ b/bgpd/bgp_pbr.h @@ -260,6 +260,7 @@ struct bgp_pbr_action { bool install_in_progress; uint32_t refcnt; struct bgp *bgp; + afi_t afi; }; extern struct bgp_pbr_rule *bgp_pbr_rule_lookup(vrf_id_t vrf_id, diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 87936f1dd6..bf32d493bc 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2356,7 +2356,10 @@ static void bgp_encode_pbr_rule_action(struct stream *s, struct bgp_pbr_rule *pbr) { struct prefix pfx; + uint8_t fam = AF_INET; + if (pbra && pbra->nh.type == NEXTHOP_TYPE_IPV6) + fam = AF_INET6; stream_putl(s, 0); /* seqno unused */ if (pbr) stream_putl(s, pbr->priority); @@ -2376,7 +2379,7 @@ static void bgp_encode_pbr_rule_action(struct stream *s, memcpy(&pfx, &(pbr->src), sizeof(struct prefix)); else { memset(&pfx, 0, sizeof(pfx)); - pfx.family = AF_INET; + pfx.family = fam; } stream_putc(s, pfx.family); stream_putc(s, pfx.prefixlen); @@ -2388,7 +2391,7 @@ static void bgp_encode_pbr_rule_action(struct stream *s, memcpy(&pfx, &(pbr->dst), sizeof(struct prefix)); else { memset(&pfx, 0, sizeof(pfx)); - pfx.family = AF_INET; + pfx.family = fam; } stream_putc(s, pfx.family); stream_putc(s, pfx.prefixlen); @@ -3063,14 +3066,14 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh, struct zapi_route api; struct prefix p; - if (!nh || nh->type != NEXTHOP_TYPE_IPV4 + if (!nh || (nh->type != NEXTHOP_TYPE_IPV4 + && nh->type != NEXTHOP_TYPE_IPV6) || nh->vrf_id == VRF_UNKNOWN) return; memset(&p, 0, sizeof(struct prefix)); - /* default route */ - if (afi != AFI_IP) + if (afi != AFI_IP && afi != AFI_IP6) return; - p.family = AF_INET; + p.family = afi2family(afi); memset(&api, 0, sizeof(api)); api.vrf_id = bgp->vrf_id; api.type = ZEBRA_ROUTE_BGP; @@ -3086,7 +3089,7 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh, SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); /* redirect IP */ - if (nh->gate.ipv4.s_addr != INADDR_ANY) { + if (afi == AFI_IP && nh->gate.ipv4.s_addr != INADDR_ANY) { char buff[PREFIX_STRLEN]; api_nh->vrf_id = nh->vrf_id; @@ -3095,7 +3098,25 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh, inet_ntop(AF_INET, &(nh->gate.ipv4), buff, INET_ADDRSTRLEN); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_info("BGP: %s default route to %s table %d (redirect IP)", + zlog_debug("BGP: %s default route to %s table %d (redirect IP)", + announce ? "adding" : "withdrawing", + buff, table_id); + zclient_route_send(announce ? ZEBRA_ROUTE_ADD + : ZEBRA_ROUTE_DELETE, + zclient, &api); + } else if (afi == AFI_IP6 && + memcmp(&nh->gate.ipv6, + &in6addr_any, sizeof(struct in6_addr))) { + char buff[PREFIX_STRLEN]; + + api_nh->vrf_id = nh->vrf_id; + memcpy(&api_nh->gate.ipv6, &nh->gate.ipv6, + sizeof(struct in6_addr)); + api_nh->type = NEXTHOP_TYPE_IPV6; + + inet_ntop(AF_INET6, &(nh->gate.ipv6), buff, INET_ADDRSTRLEN); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("BGP: %s default route to %s table %d (redirect IP)", announce ? "adding" : "withdrawing", buff, table_id); zclient_route_send(announce ? ZEBRA_ROUTE_ADD