]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: Handle role capability using dynamic capability
authorDonatas Abraitis <donatas@opensourcerouting.org>
Sat, 5 Aug 2023 19:32:57 +0000 (22:32 +0300)
committerDonatas Abraitis <donatas@opensourcerouting.org>
Sat, 5 Aug 2023 19:44:45 +0000 (22:44 +0300)
When setting local-role for the neighbor, force sending ROLE capability via
dynamic capability if it's enabled.

Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
bgpd/bgp_packet.c
bgpd/bgp_vty.c
bgpd/bgpd.c

index 7c2c6f616be74d6fd04a11d54683d6975e012e62..fcd644a21007d79a1d4bf01fa97d822ac5c4dc10 100644 (file)
@@ -1272,7 +1272,15 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
        case CAPABILITY_CODE_FQDN:
        case CAPABILITY_CODE_ENHE:
        case CAPABILITY_CODE_EXT_MESSAGE:
+               break;
        case CAPABILITY_CODE_ROLE:
+               if (peer->local_role != ROLE_UNDEFINED) {
+                       SET_FLAG(peer->cap, PEER_CAP_ROLE_ADV);
+                       stream_putc(s, action);
+                       stream_putc(s, CAPABILITY_CODE_ROLE);
+                       stream_putc(s, CAPABILITY_CODE_ROLE_LEN);
+                       stream_putc(s, peer->local_role);
+               }
                break;
        default:
                break;
@@ -2876,7 +2884,22 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
                case CAPABILITY_CODE_FQDN:
                case CAPABILITY_CODE_ENHE:
                case CAPABILITY_CODE_EXT_MESSAGE:
+                       break;
                case CAPABILITY_CODE_ROLE:
+                       SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV);
+                       if (hdr->length != CAPABILITY_CODE_ROLE_LEN) {
+                               flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH,
+                                         "Role: Received invalid length %d",
+                                         hdr->length);
+                               bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+                                               BGP_NOTIFY_SUBCODE_UNSPECIFIC);
+                               return BGP_Stop;
+                       }
+                       uint8_t role;
+
+                       memcpy(&role, pnt + 3, sizeof(role));
+
+                       peer->remote_role = role;
                        break;
                default:
                        flog_warn(
index 591e0c396938d149250d18cad7340b55a8f5ba4d..52c9b95992d4569be3a97600cc872431ce0ed0e1 100644 (file)
@@ -6786,14 +6786,9 @@ static uint8_t get_role_by_name(const char *role_str)
        return ROLE_UNDEFINED;
 }
 
-static int peer_role_set_vty(struct vty *vty, const char *ip_str,
+static int peer_role_set_vty(struct vty *vty, struct peer *peer,
                             const char *role_str, bool strict_mode)
 {
-       struct peer *peer;
-
-       peer = peer_and_group_lookup_vty(vty, ip_str);
-       if (!peer)
-               return CMD_WARNING_CONFIG_FAILED;
        uint8_t role = get_role_by_name(role_str);
 
        if (role == ROLE_UNDEFINED)
@@ -6801,50 +6796,66 @@ static int peer_role_set_vty(struct vty *vty, const char *ip_str,
        return bgp_vty_return(vty, peer_role_set(peer, role, strict_mode));
 }
 
-static int peer_role_unset_vty(struct vty *vty, const char *ip_str)
-{
-       struct peer *peer;
-
-       peer = peer_and_group_lookup_vty(vty, ip_str);
-       if (!peer)
-               return CMD_WARNING_CONFIG_FAILED;
-       return bgp_vty_return(vty, peer_role_unset(peer));
-}
-
 DEFPY(neighbor_role,
       neighbor_role_cmd,
-      "neighbor <A.B.C.D|X:X::X:X|WORD> local-role <provider|rs-server|rs-client|customer|peer>",
+      "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor local-role <provider|rs-server|rs-client|customer|peer>$role",
       NEIGHBOR_STR
       NEIGHBOR_ADDR_STR2
       "Set session role\n"
       ROLE_STR)
 {
-       int idx_peer = 1;
-       int idx_role = 3;
+       int ret;
+       struct peer *peer;
+
+       peer = peer_and_group_lookup_vty(vty, neighbor);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       ret = peer_role_set_vty(vty, peer, role, false);
+
+       if (peer_established(peer)) {
+               if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) &&
+                   CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV))
+                       bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
+                                           CAPABILITY_CODE_ROLE,
+                                           CAPABILITY_ACTION_SET);
+       }
 
-       return peer_role_set_vty(vty, argv[idx_peer]->arg, argv[idx_role]->arg,
-                                false);
+       return ret;
 }
 
 DEFPY(neighbor_role_strict,
       neighbor_role_strict_cmd,
-      "neighbor <A.B.C.D|X:X::X:X|WORD> local-role <provider|rs-server|rs-client|customer|peer> strict-mode",
+      "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor local-role <provider|rs-server|rs-client|customer|peer>$role strict-mode",
       NEIGHBOR_STR
       NEIGHBOR_ADDR_STR2
       "Set session role\n"
       ROLE_STR
       "Use additional restriction on peer\n")
 {
-       int idx_peer = 1;
-       int idx_role = 3;
+       int ret;
+       struct peer *peer;
+
+       peer = peer_and_group_lookup_vty(vty, neighbor);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
 
-       return peer_role_set_vty(vty, argv[idx_peer]->arg, argv[idx_role]->arg,
-                                true);
+       ret = peer_role_set_vty(vty, peer, role, true);
+
+       if (peer_established(peer)) {
+               if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) &&
+                   CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV))
+                       bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
+                                           CAPABILITY_CODE_ROLE,
+                                           CAPABILITY_ACTION_SET);
+       }
+
+       return ret;
 }
 
 DEFPY(no_neighbor_role,
       no_neighbor_role_cmd,
-      "no neighbor <A.B.C.D|X:X::X:X|WORD> local-role <provider|rs-server|rs-client|customer|peer> [strict-mode]",
+      "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor local-role <provider|rs-server|rs-client|customer|peer> [strict-mode]",
       NO_STR
       NEIGHBOR_STR
       NEIGHBOR_ADDR_STR2
@@ -6852,9 +6863,24 @@ DEFPY(no_neighbor_role,
       ROLE_STR
       "Use additional restriction on peer\n")
 {
-       int idx_peer = 2;
+       int ret;
+       struct peer *peer;
+
+       peer = peer_and_group_lookup_vty(vty, neighbor);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       ret = bgp_vty_return(vty, peer_role_unset(peer));
 
-       return peer_role_unset_vty(vty, argv[idx_peer]->arg);
+       if (peer_established(peer)) {
+               if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) &&
+                   CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV))
+                       bgp_capability_send(peer, AFI_IP, SAFI_UNICAST,
+                                           CAPABILITY_CODE_ROLE,
+                                           CAPABILITY_ACTION_UNSET);
+       }
+
+       return ret;
 }
 
 /* disable-connected-check */
index b72e75d12e622ae420d122b4b51da526da8c7e53..aaf1f41c4b117f36624581e447f6ab6ecc0bd556 100644 (file)
@@ -4444,8 +4444,8 @@ static const struct peer_flag_action peer_flag_action_list[] = {
        {PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none},
        {PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE, 0, peer_change_none},
        {PEER_FLAG_EXTENDED_OPT_PARAMS, 0, peer_change_reset},
-       {PEER_FLAG_ROLE_STRICT_MODE, 0, peer_change_reset},
-       {PEER_FLAG_ROLE, 0, peer_change_reset},
+       {PEER_FLAG_ROLE_STRICT_MODE, 0, peer_change_none},
+       {PEER_FLAG_ROLE, 0, peer_change_none},
        {PEER_FLAG_PORT, 0, peer_change_reset},
        {PEER_FLAG_AIGP, 0, peer_change_none},
        {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none},
@@ -5167,7 +5167,6 @@ int peer_role_set(struct peer *peer, uint8_t role, bool strict_mode)
                        else
                                UNSET_FLAG(peer->flags,
                                           PEER_FLAG_ROLE_STRICT_MODE);
-                       bgp_session_reset(peer);
                }
 
                return CMD_SUCCESS;
@@ -5212,7 +5211,6 @@ int peer_role_set(struct peer *peer, uint8_t role, bool strict_mode)
                                UNSET_FLAG(member->flags,
                                           PEER_FLAG_ROLE_STRICT_MODE);
                        }
-                       bgp_session_reset(member);
                }
        }