Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
556 changes: 556 additions & 0 deletions doc/modular-chassis-voq/centralized_ipc_hld.md

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
113 changes: 113 additions & 0 deletions doc/modular-chassis-voq/img/figure_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""Shared drawing helpers for §8 Operational IPC flow figures."""

from PIL import Image, ImageDraw, ImageFont

W = 1536
BG = (255, 255, 255)
GRID = (220, 220, 220)
TEXT = (30, 30, 30)
MUTED = (90, 90, 90)
ARROW = (60, 60, 60)

# Figure 5 reference participants (hub → spoke)
HUB_PARTICIPANTS = [
("Application\ndaemon", (66, 133, 244)),
("ProducerStateTable", (142, 68, 173), "(zmqEnhanced path for IPC-carried tables)"),
("Central Application\nDatabase", (231, 76, 60)),
("Midplane message\nproxy", (230, 126, 34)),
("zmqEnhanced\nconsumer", (39, 174, 96), "(one per IPC-carried table)"),
("orchagent", (52, 152, 219), "(host consumer)"),
("ASIC", (127, 140, 141)),
]

PST = ("ProducerStateTable", (142, 68, 173), "(zmqEnhanced path)")
DB = ("Central Application\nDatabase", (231, 76, 60))
PROXY = ("Midplane message\nproxy", (230, 126, 34))
CONSUMER = ("zmqEnhanced\nconsumer", (39, 174, 96), "(one per IPC-carried table)")
ORCH = ("orchagent", (52, 152, 219), "(host consumer)")


def load_font(size: int, bold: bool = False):
candidates = [
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" if bold else "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf" if bold else "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
]
for path in candidates:
try:
return ImageFont.truetype(path, size)
except OSError:
continue
return ImageFont.load_default()


def wrap_center(draw, text, cx, y, font, fill=TEXT, line_gap=4):
lines = text.split("\n")
cy = y
for line in lines:
bbox = draw.textbbox((0, 0), line, font=font)
w = bbox[2] - bbox[0]
h = bbox[3] - bbox[1]
draw.text((cx - w / 2, cy), line, font=font, fill=fill)
cy += h + line_gap
return cy - y


def draw_title_block(draw, title, subtitle, title_font, sub_font):
bbox = draw.textbbox((0, 0), title, font=title_font)
draw.text(((W - (bbox[2] - bbox[0])) / 2, 24), title, font=title_font, fill=TEXT)
bbox = draw.textbbox((0, 0), subtitle, font=sub_font)
draw.text(((W - (bbox[2] - bbox[0])) / 2, 62), subtitle, font=sub_font, fill=MUTED)


def draw_participants(draw, participants, margin_x=48, top_y=110, header_h=92, width=W, img_h=918):
n = len(participants)
col_w = (width - 2 * margin_x) / n
xs = [margin_x + col_w * (i + 0.5) for i in range(n)]
head_font = load_font(15, bold=True)
subhead_font = load_font(12)
for i, p in enumerate(participants):
color = p[1]
x0 = margin_x + col_w * i + 6
x1 = margin_x + col_w * (i + 1) - 6
draw.rounded_rectangle([x0, top_y, x1, top_y + header_h], radius=10, fill=color + (40,), outline=color, width=2)
wrap_center(draw, p[0], xs[i], top_y + 14, head_font, fill=TEXT)
if len(p) > 2:
wrap_center(draw, p[2], xs[i], top_y + 52, subhead_font, fill=MUTED)
lifeline_top = top_y + header_h + 8
lane_bottom = img_h - 36
for x in xs:
for y in range(lifeline_top, lane_bottom, 10):
draw.line([(x, y), (x, min(y + 5, lane_bottom))], fill=GRID, width=2)
return xs, lifeline_top


def draw_arrow(draw, xs, y, src, dst, label, step_font, dashed=False):
x0, x1 = xs[src], xs[dst]
if dashed:
for x in range(int(min(x0, x1)), int(max(x0, x1)), 14):
x_end = min(x + 8, max(x0, x1))
draw.line([(x, y), (x_end, y)], fill=ARROW, width=2)
else:
draw.line([(x0, y), (x1, y)], fill=ARROW, width=2)
if x1 > x0:
draw.polygon([(x1, y), (x1 - 10, y - 5), (x1 - 10, y + 5)], fill=ARROW)
else:
draw.polygon([(x1, y), (x1 + 10, y - 5), (x1 + 10, y + 5)], fill=ARROW)
wrap_center(draw, label, (x0 + x1) / 2, y - 28, step_font, fill=TEXT)


def draw_ladder(img_h, participants, steps, gaps, title, subtitle):
img = Image.new("RGB", (W, img_h), BG)
draw = ImageDraw.Draw(img)
title_font = load_font(28, bold=True)
sub_font = load_font(16)
step_font = load_font(14)
draw_title_block(draw, title, subtitle, title_font, sub_font)
xs, lifeline_top = draw_participants(draw, participants, top_y=110, header_h=92, img_h=img_h)
y = lifeline_top + 55
for idx, step in enumerate(steps):
src, dst, label = step[0], step[1], step[2]
dashed = len(step) > 3 and step[3]
draw_arrow(draw, xs, y, src, dst, label, step_font, dashed=dashed)
y += gaps[idx]
return img
104 changes: 104 additions & 0 deletions doc/modular-chassis-voq/img/gen_frame_envelope_figure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env python3
"""Generate §7.1 Frame Envelope figure — database : table : frame kind : payload."""

import os

from PIL import Image, ImageDraw

from figure_common import BG, MUTED, TEXT, load_font, wrap_center

IMG_DIR = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(IMG_DIR, "centralized_ipc_frame_envelope.png")

IMG_W = 1024
IMG_H = 210

C_DB = (66, 133, 244)
C_TABLE = (142, 68, 173)
C_KIND = (230, 126, 34)
C_PAYLOAD = (39, 174, 96)
C_FRAME = (120, 120, 140)


def draw_title_block(draw, title, subtitle, title_font, sub_font, width):
bbox = draw.textbbox((0, 0), title, font=title_font)
draw.text(((width - (bbox[2] - bbox[0])) / 2, 12), title, font=title_font, fill=TEXT)
bbox = draw.textbbox((0, 0), subtitle, font=sub_font)
draw.text(((width - (bbox[2] - bbox[0])) / 2, 38), subtitle, font=sub_font, fill=MUTED)


def segment(draw, x, y, w, h, title, value, color, title_font, value_font):
draw.rounded_rectangle([x, y, x + w, y + h], radius=10, outline=color, width=2, fill=(255, 255, 255))
# color accent bar
draw.rounded_rectangle([x + 2, y + 2, x + w - 2, y + 24], radius=8, fill=color + (48,))
wrap_center(draw, title, x + w / 2, y + 5, title_font, fill=TEXT)
wrap_center(draw, value, x + w / 2, y + h // 2 + 6, value_font, fill=TEXT)


def colon(draw, x, y, font):
bbox = draw.textbbox((0, 0), ":", font=font)
tw = bbox[2] - bbox[0]
th = bbox[3] - bbox[1]
draw.text((x - tw / 2, y - th / 2), ":", font=font, fill=(100, 100, 100))


def main():
title_font = load_font(22, bold=True)
sub_font = load_font(13)
seg_title_font = load_font(12, bold=True)
value_font = load_font(15, bold=True)
colon_font = load_font(22, bold=True)

img = Image.new("RGB", (IMG_W, IMG_H), BG)
draw = ImageDraw.Draw(img)
draw_title_block(
draw,
"Midplane Frame Envelope",
"Logical layout of every data frame on the midplane bus",
title_font,
sub_font,
IMG_W,
)

margin = 40
frame_x = margin
frame_y = 68
frame_w = IMG_W - 2 * margin
frame_h = 100
draw.rounded_rectangle(
[frame_x, frame_y, frame_x + frame_w, frame_y + frame_h],
radius=12,
outline=C_FRAME,
width=2,
fill=(250, 251, 253),
)
wrap_center(draw, "Midplane data frame", frame_x + frame_w / 2, frame_y + 10, seg_title_font, fill=MUTED)

inner_y = frame_y + 28
inner_h = frame_h - 34
gap = 16
n_cols = 4
total_gap = gap * (n_cols - 1) + 28 # colons + padding
col_w = (frame_w - total_gap) // n_cols
x = frame_x + 14

cols = [
("Database", "APPL_DB", C_DB),
("Table", "ROUTE_TABLE", C_TABLE),
("Frame kind", "single | batch", C_KIND),
("Payload", "set / delete …", C_PAYLOAD),
]

for i, (title, value, color) in enumerate(cols):
segment(draw, x, inner_y, col_w, inner_h, title, value, color, seg_title_font, value_font)
x += col_w
if i < n_cols - 1:
colon(draw, x + gap / 2, inner_y + inner_h / 2, colon_font)
x += gap

img.save(OUT, "PNG")
print("Wrote", OUT, f"({IMG_W}x{IMG_H})")


if __name__ == "__main__":
main()
146 changes: 146 additions & 0 deletions doc/modular-chassis-voq/img/gen_ipc_queueing_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#!/usr/bin/env python3
"""Figure 6 — queues sit beside the vertical connector (socket on the wire)."""

import os

from PIL import Image, ImageDraw

from figure_common import BG, MUTED, TEXT, W, draw_title_block, load_font, wrap_center

IMG_DIR = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(IMG_DIR, "centralized_ipc_queueing_stack.png")

C_PST = (142, 68, 173)
C_PROXY = (230, 126, 34)
C_CONSUMER = (39, 174, 96)
C_ORCH = (52, 152, 219)
C_ARROW = (60, 60, 60)
Q_ZMQ = (230, 126, 34)
Q_INPROC = (142, 68, 173)
C_SAT_BG = (241, 245, 249)
C_SAT_BORDER = (203, 213, 225)
C_SAT_TEXT = (71, 85, 105)


def fig1_box(draw, x, y, w, h, title, color, font):
draw.rounded_rectangle([x, y, x + w, y + h], radius=10, outline=color, width=2, fill=color + (40,))
bbox = draw.textbbox((0, 0), title, font=font)
th = bbox[3] - bbox[1]
draw.text((x + (w - (bbox[2] - bbox[0])) / 2, y + (h - th) / 2 - 1), title, font=font, fill=TEXT)


def sat_badge(draw, x, y, num, font):
label = str(num)
tw = draw.textbbox((0, 0), label, font=font)[2]
r = 11
draw.ellipse([x - r, y - r, x + r, y + r], fill=C_SAT_BG, outline=C_SAT_BORDER, width=1)
draw.text((x - tw / 2, y - 6), label, font=font, fill=C_SAT_TEXT)


def draw_socket_queue(draw, x, y, w, h, color, n_slabs=5, sat=None, sat_f=None):
"""Vertical queue stack — sits beside the connector arrow."""
draw.rounded_rectangle([x, y, x + w, y + h], radius=6, outline=color, width=2, fill=(252, 253, 255))
pad = 4
slab_h = max(4, (h - pad * 2 - (n_slabs - 1) * 2) // n_slabs)
sy = y + h - pad - slab_h
for i in range(n_slabs):
t = 45 + i * 22
fill = tuple(min(255, int(c * (1 - t / 255) + 255 * (t / 255))) for c in color)
draw.rounded_rectangle([x + pad, sy, x + w - pad, sy + slab_h], radius=2, outline=color, width=1, fill=fill)
sy -= slab_h + 2
if sat is not None:
sat_badge(draw, x + w + 2, y + 4, sat, sat_f)


def arrow_v(draw, x, y0, y1):
draw.line([(x, y0 + 2), (x, y1 - 10)], fill=C_ARROW, width=2)
draw.polygon([(x, y1 - 4), (x - 5, y1 - 12), (x + 5, y1 - 12)], fill=C_ARROW)


def connector_with_queue(draw, lane_x, y, conn_h, color, sat, sat_f, q_w=54, q_h=48):
"""Vertical arrow with single queue beside it — socket on the wire."""
y1 = y + conn_h
arrow_v(draw, lane_x, y, y1)
qx = lane_x + 20
qy = y + (conn_h - q_h) // 2
draw_socket_queue(draw, qx, qy, q_w, q_h, color, n_slabs=5, sat=sat, sat_f=sat_f)
return y1


def connector_with_fanout_queues(draw, lane_x, y, conn_h, color, sat, sat_f, label_f):
"""XPUB fan-out — queue1, queue2, …, queue-n beside the connector."""
y1 = y + conn_h
arrow_v(draw, lane_x, y, y1)

q_w, q_h = 42, 38
gap = 6
ell_w = 14
labels = ["queue1", "queue2", "queue-n"]
n_queues = 3
group_w = n_queues * q_w + (n_queues - 1) * gap + ell_w + gap
qx = lane_x + 20
qy = y + 6

sat_badge(draw, qx + group_w - 2, qy - 2, sat, sat_f)

x = qx
for i, lbl in enumerate(labels):
if i == 2:
draw.text((x + 2, qy + q_h // 2 - 6), "…", font=label_f, fill=MUTED)
x += ell_w + gap
draw_socket_queue(draw, x, qy, q_w, q_h, color, n_slabs=4)
tw = draw.textbbox((0, 0), lbl, font=label_f)[2]
draw.text((x + (q_w - tw) / 2, qy + q_h + 3), lbl, font=label_f, fill=MUTED)
x += q_w + gap

return y1


def main():
lane_x = W // 2
box_w = 380
box_h = 56
box_x = lane_x - box_w // 2
conn = 62
q_w, q_h = 54, 48

title_f = load_font(26, bold=True)
sub_f = load_font(14)
box_f = load_font(14, bold=True)
cap_f = load_font(12)
sat_f = load_font(10, bold=True)
q_label_f = load_font(9)

img = Image.new("RGB", (W, 580), BG)
draw = ImageDraw.Draw(img)

draw_title_block(draw, "Queueing Across the IPC Stack",
"Saturation points on the steady-state path", title_f, sub_f)

y = 92

fig1_box(draw, box_x, y, box_w, box_h, "ProducerStateTable", C_PST, box_f)
y += box_h
y = connector_with_queue(draw, lane_x, y, conn, Q_ZMQ, 1, sat_f, q_w, q_h)

fig1_box(draw, box_x, y, box_w, box_h, "Midplane message proxy", C_PROXY, box_f)
y += box_h
y = connector_with_fanout_queues(draw, lane_x, y, conn, Q_ZMQ, 2, sat_f, q_label_f)

fig1_box(draw, box_x, y, box_w, box_h, "zmqEnhanced consumer", C_CONSUMER, box_f)
y += box_h
y = connector_with_queue(draw, lane_x, y, conn, Q_INPROC, 3, sat_f, q_w, q_h)

fig1_box(draw, box_x, y, box_w, box_h, "orchagent", C_ORCH, box_f)
y += box_h + 24

wrap_center(draw, "Figure — Saturation queues ① PUB ② XPUB ③ received-op",
lane_x, y, cap_f, fill=MUTED)

img = img.crop((0, 0, W, y + 24))
img.save(OUT, "PNG")
print(f"Wrote {OUT} ({img.size[0]}x{img.size[1]})")


if __name__ == "__main__":
main()
Loading