]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: support for redirect ipv6 simpson method
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 16 Oct 2019 08:05:36 +0000 (10:05 +0200)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 21 Aug 2020 11:37:08 +0000 (13:37 +0200)
this commit supports [0] where ipv6 address is encoded in nexthop
attribute of nlri, and not in bgp redirect ip extended community. the
community contains only duplicate information or not.
Adding to this, because an action or a rule needs to apply to either
ipv4 or ipv6 flow, modify some internal structures so as to be aware of
which flow needs to be filtered. This work is needed when an ipv6
flowspec rule without ip addresses is mentioned, we need to know which
afi is served. Also, this work will be useful when doing redirect VRF.

[0] draft-simpson-idr-flowspec-redirect-02.txt

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
bgpd/bgp_ecommunity.c
bgpd/bgp_ecommunity.h
bgpd/bgp_flowspec_vty.c
bgpd/bgp_pbr.c
bgpd/bgp_pbr.h
bgpd/bgp_zebra.c

index f2aac3646c899e57b9943d252bb28b75c8ea993e..c7fabb396a3e3b3db9eba40778e4ceb2f19b4a9e 100644 (file)
@@ -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:
index 812bcc46e7571cecb0b31981105745c2da28e5ed..8ae3b44babb1002f05b3d3e38cb1b8bb340ecd28 100644 (file)
@@ -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,
index 4b1d26b2fea160c1a64fc8e3d93a0d9148770651..3e3366bf8b2d8055b0db26f95bf51946511e0468 100644 (file)
@@ -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);
index 715781143fc095b4eb35a7f3e7e23cb104f56b8a..9446575611051df8314e0bf0be60c927c8135a53 100644 (file)
@@ -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
index 403300dc039298ac5e1c702660dd11c0aca12441..ff333d2f109a42f329557e7b30882be626553d99 100644 (file)
@@ -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,
index 87936f1dd6d3f47944798bf1d2dad30f3913b081..bf32d493bc4eaf0d5da72200a0af255be7104fe8 100644 (file)
@@ -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