## file: src/sonic-utilities/utilities_common/bgp_util.py defget_bgp_summary_from_all_bgp_instances(af, namespace, display): # IPv6 case is emitted here for simplicity vtysh_cmd = "show ip bgp summary json" for ns in device.get_ns_list_based_on_options(): cmd_output = run_bgp_show_command(vtysh_cmd, ns)
root@7260cx3:/etc/sonic/frr# which vtysh /usr/bin/vtysh
root@7260cx3:/etc/sonic/frr# vtysh
Hello, this is FRRouting (version 7.5.1-sonic). Copyright 1996-2005 Kunihiro Ishiguro, et al.
7260cx3# show ip bgp summary
IPv4 Unicast Summary: BGP router identifier 10.1.0.32, local AS number 65100 vrf-id 0 BGP table version 6410 RIB entries 12809, using 2402 KiB of memory Peers 4, using 85 KiB of memory Peer groups 4, using 256 bytes of memory
@bgp.group(cls=clicommon.AbbreviationGroup) defremove(): "Remove BGP neighbor configuration from the device" pass
@remove.command('neighbor') @click.argument('neighbor_ip_or_hostname', metavar='<neighbor_ip_or_hostname>', required=True) defremove_neighbor(neighbor_ip_or_hostname): """Deletes BGP neighbor configuration of given hostname or ip from devices User can specify either internal or external BGP neighbor to remove """ namespaces = [DEFAULT_NAMESPACE] removed_neighbor = False ...
# Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the # namespaces (in case of multi ASIC) and do the sepcified "action" on the BGP neighbor(s) for namespace in namespaces: config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() if _remove_bgp_neighbor_config(config_db, neighbor_ip_or_hostname): removed_neighbor = True ...
sequenceDiagram
autonumber
participant N as 邻居节点
box lightblue bgp容器
participant B as bgpd
participant ZH as zebra<br/>(请求处理线程)
participant ZF as zebra<br/>(路由处理线程)
participant ZD as zebra<br/>(数据平面处理线程)
participant ZFPM as zebra<br/>(FPM转发线程)
participant FPM as fpmsyncd
end
participant K as Linux Kernel
N->>B: 建立BGP会话,<br/>发送路由变更
B->>B: 选路,变更本地路由表(RIB)
alt 如果路由发生变化
B->>N: 通知其他邻居节点路由变化
end
B->>ZH: 通过zlient本地Socket<br/>通知Zebra更新路由表
ZH->>ZH: 接受bgpd发送的请求
ZH->>ZF: 将路由请求放入<br/>路由处理线程的队列中
ZF->>ZF: 更新本地路由表(RIB)
ZF->>ZD: 将路由表更新请求放入<br/>数据平面处理线程<br/>的消息队列中
ZF->>ZFPM: 请求FPM处理线程转发路由变更
ZFPM->>FPM: 通过FPM协议通知<br/>fpmsyncd下发<br/>路由变更
ZD->>K: 发送Netlink消息更新内核路由表
while (more) { // Read packets here ... // If we have more than 1 complete packet, mark it and process it later. if (ringbuf_remain(ibw) >= pktsize) { ... added_pkt = true; } elsebreak; } ...
if (added_pkt) thread_add_event(bm->master, bgp_process_packet, peer, 0, &peer->t_process_packet);
// File: src/sonic-frr/frr/bgpd/bgp_route.c /* Process the routes with the flag BGP_NODE_SELECT_DEFER set */ intbgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) { structbgp_dest *dest; int cnt = 0; structafi_safi_info *thread_info; ...
/* Process the route list */ for (dest = bgp_table_top(bgp->rib[afi][safi]); dest && bgp->gr_info[afi][safi].gr_deferred != 0; dest = bgp_route_next(dest)) { ... bgp_process_main_one(bgp, dest, afi, safi); ... } ...
// Decode zclient request s = msg; if (zapi_route_decode(s, &api) < 0) { return; } ...
// Allocate new route entry. re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); re->type = api.type; re->instance = api.instance; ... // Init nexthop entry, if we have an id, then add route. if (!re->nhe_id) { zebra_nhe_init(&nhe, afi, ng->nexthop); nhe.nhg.nexthop = ng->nexthop; nhe.backup_info = bnhg; } ret = rib_add_multipath_nhe(afi, api.safi, &api.prefix, src_p, re, &nhe);
// Update stats. IPv6 is emitted here for simplicity. if (ret > 0) client->v4_route_add_cnt++; elseif (ret < 0) client->v4_route_upd8_cnt++; }
/* If this route is kernel/connected route, notify the dataplane to update kernel route table. */ if (RIB_SYSTEM_ROUTE(re)) { dplane_sys_route_add(rn, re); }
/* Link new re to node. */ SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); rib_addnode(rn, re, 1);
/* Clean up */ ... return ret; }
rib_addnode会将这个路由添加请求转发给rib的处理线程,并由它顺序的进行处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
staticvoidrib_addnode(struct route_node *rn, struct route_entry *re, int process) { ... rib_link(rn, re, process); } staticvoidrib_link(struct route_node *rn, struct route_entry *re, int process) { rib_dest_t *dest = rib_dest_from_rnode(rn); if (!dest) dest = zebra_rib_create_dest(rn); re_list_add_head(&dest->routes, re); ...
/* Install the resolved nexthop object first. */ zebra_nhg_install_kernel(re->nhe);
/* If this is a replace to a new RE let the originator of the RE know that they've lost */ if (old && (old != re) && (old->type != re->type)) zsend_route_notify_owner(rn, old, ZAPI_ROUTE_BETTER_ADMIN_WON, info->afi, info->safi);
for (counter = 0; counter < limit; counter++) { ctx = dplane_provider_dequeue_in_ctx(prov); if (ctx == NULL) break;
/* A previous provider plugin may have asked to skip the kernel update. */ if (dplane_ctx_is_skip_kernel(ctx)) { res = ZEBRA_DPLANE_REQUEST_SUCCESS; goto skip_one; }
/* Dispatch to appropriate kernel-facing apis */ switch (dplane_ctx_get_op(ctx)) { case DPLANE_OP_ROUTE_INSTALL: case DPLANE_OP_ROUTE_UPDATE: case DPLANE_OP_ROUTE_DELETE: res = kernel_dplane_route_update(ctx); break; ... } ... } ... }
staticenum zebra_dplane_result kernel_dplane_route_update(struct zebra_dplane_ctx *ctx) { enumzebra_dplane_resultres; /* Call into the synchronous kernel-facing code here */ res = kernel_route_update(ctx); return res; }
// File: src/sonic-frr/frr/zebra/rt_netlink.c // Update or delete a prefix from the kernel, using info from a dataplane context. enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) { int cmd, ret; conststructprefix *p = dplane_ctx_get_dest(ctx); structnexthop *nexthop;
do { int bytes_to_write, bytes_written; s = zfpm_g->obuf;
// Convert route info to buffer here. if (stream_empty(s)) zfpm_build_updates();
// Write to socket until we don' have anything to write or cannot write anymore (partial write). bytes_to_write = stream_get_endp(s) - stream_get_getp(s); bytes_written = write(zfpm_g->sock, stream_pnt(s), bytes_to_write); ... } while (1);
if (zfpm_writes_pending()) zfpm_write_on(); return0; }
staticvoidzfpm_build_updates(void) { structstream *s = zfpm_g->obuf; do { /* Stop processing the queues if zfpm_g->obuf is full or we do not have more updates to process */ if (zfpm_build_mac_updates() == FPM_WRITE_STOP) break; if (zfpm_build_route_updates() == FPM_WRITE_STOP) break; } while (zfpm_updates_pending()); }