DF-0753 / mpls_trigger.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /* * DF-0753 live trigger attempt. * * Injects an MPLS frame via bpf BIOCSFEEDBACK on vtnet0 to exercise * mpls_input -> mpls_forward -> mpls_output(PUSH) on a live kernel * with mpls.ko loaded. * * Per source analysis (sys/netproto/mpls/mpls_output.c:157 M_PREPEND + * sys/kern/uipc_mbuf.c:1500 m_prepend + mbuf.h:446 M_LEADINGSPACE): * ether_input always leaves ETHER_HDR_LEN (14) bytes of leading space; * MPLS_MAXLOPS=3 * 4 = 12 < 14, so PUSH never calls m_prepend on * standard ethernet-received frames. This trigger confirms that * EMPIRICALLY (no panic on standard frames) — the deterministic proof * is in mpls_stale_harness.c. * * Usage: ./mpls_trigger <ifname> (default vtnet0) * Requires root to open /dev/bpf. */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <fcntl.h> #include <net/if.h> #include <net/bpf.h> #include <net/ethernet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <err.h> #ifndef ETHERTYPE_MPLS #define ETHERTYPE_MPLS 0x8847 #endif int main(int argc, char **argv) { const char *ifname = (argc > 1) ? argv[1] : "vtnet0"; char dev[16]; int fd, i, n; struct ifreq ifr; u_int dlt; u_int imm = 1; for (i = 0; i < 16; i++) { snprintf(dev, sizeof(dev), "/dev/bpf%d", i); fd = open(dev, O_RDWR); if (fd >= 0) break; } if (fd < 0) err(1, "open bpf"); memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, &ifr) < 0) err(1, "BIOCSETIF %s", ifname); if (ioctl(fd, BIOCIMMEDIATE, &imm) < 0) err(1, "BIOCIMMEDIATE"); if (ioctl(fd, BIOCSFEEDBACK, &imm) < 0) err(1, "BIOCSFEEDBACK"); imm = 1; if (ioctl(fd, BIOCSHDRCMPLT, &imm) < 0) err(1, "BIOCSHDRCMPLT"); if (ioctl(fd, BIOCGDLT, &dlt) < 0) err(1, "BIOCGDLT"); if (dlt != DLT_EN10MB) errx(1, "unexpected datalink type %u", dlt); /* * Frame: dst=broadcast, src=vtnet0, ethertype=0x8847, * then a single MPLS label (label=100, S=1, TTL=64) + 20 bytes * payload. This is a bottom-of-stack MPLS frame that mpls_input * will try to forward via mpls_forward -> mpls_output. */ unsigned char frame[64]; memset(frame, 0, sizeof(frame)); memset(frame + 0, 0xff, 6); /* dst = broadcast */ frame[6] = 0x52; frame[7] = 0x54; frame[8] = 0x00; /* src */ frame[9] = 0x12; frame[10] = 0x34; frame[11] = 0x56; frame[12] = 0x88; frame[13] = 0x47; /* ethertype MPLS */ /* MPLS shim: label=100 (0x064), exp=0, S=1, TTL=64 */ /* big-endian: (100<<12)|(1<<8)|64 = 0x000641 */ frame[14] = 0x00; frame[15] = 0x06; frame[16] = 0x41; frame[17] = 0x40; printf("DF-0753: injecting 1 MPLS frame (%zu bytes) label=100 S=1 TTL=64 on %s\n", sizeof(frame), ifname); fflush(stdout); n = write(fd, frame, sizeof(frame)); if (n < 0) err(1, "write bpf"); printf("DF-0753: write returned %d\n", n); printf("DF-0753: if mpls_forward + PUSH route is configured, mpls_output runs.\n"); printf("DF-0753: with 14-byte ether headroom >= max 12-byte PUSH, NO realloc expected.\n"); fflush(stdout); close(fd); return 0; } |