@@ -121,6 +121,98 @@ struct sock_filter dhcp_sock_filter [] = {
121
121
BPF_STMT (BPF_RET + BPF_K, 0 ),
122
122
};
123
123
124
+ // / The following structure defines a Berkeley Packet Filter program to perform
125
+ // / packet filtering. The program operates on IPoIB pseudo packets. To help with
126
+ // / interpretation of the program, for the types of packets we are interested
127
+ // / in, the header layout is:
128
+ // /
129
+ // / 20 bytes Source Interface Address
130
+ // / 2 bytes Packet Type
131
+ // / 2 bytes Reserved/Unused
132
+ // /
133
+ // / The rest is identical to aboves Ethernet-Based packets
134
+ // /
135
+ // / Each instruction is preceded with the comments giving the instruction
136
+ // / number within a BPF program, in the following format: #123.
137
+
138
+ struct sock_filter dhcp_sock_filter_ib [] = {
139
+ // Make sure this is an IP packet: check the half-word (two bytes)
140
+ // at offset 20 in the packet (the IPoIB pseudo packet type). If it
141
+ // is, advance to the next instruction. If not, advance 11
142
+ // instructions (which takes execution to the last instruction in
143
+ // the sequence: "drop it").
144
+ // #0
145
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, IPOIB_PACKET_TYPE_OFFSET),
146
+ // #1
147
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0 , 11 ),
148
+
149
+ // Make sure it's a UDP packet. The IP protocol is at offset
150
+ // 9 in the IP header so, adding the IPoIB packet header size
151
+ // of 24 bytes gives an absolute byte offset in the packet of 33.
152
+ // #2
153
+ BPF_STMT (BPF_LD + BPF_B + BPF_ABS,
154
+ IPOIB_HEADER_LEN + IP_PROTO_TYPE_OFFSET),
155
+ // #3
156
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0 , 9 ),
157
+
158
+ // Make sure this isn't a fragment by checking that the fragment
159
+ // offset field in the IP header is zero. This field is the
160
+ // least-significant 13 bits in the bytes at offsets 6 and 7 in
161
+ // the IP header, so the half-word at offset 30 (6 + size of
162
+ // IPoIB header) is loaded and an appropriate mask applied.
163
+ // #4
164
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, IPOIB_HEADER_LEN + IP_FLAGS_OFFSET),
165
+ // #5
166
+ BPF_JUMP (BPF_JMP + BPF_JSET + BPF_K, 0x1fff , 7 , 0 ),
167
+
168
+ // Check the packet's destination address. The program will only
169
+ // allow the packets sent to the broadcast address or unicast
170
+ // to the specific address on the interface. By default, this
171
+ // address is set to 0 and must be set to the specific value
172
+ // when the raw socket is created and the program is attached
173
+ // to it. The caller must assign the address to the
174
+ // prog.bf_insns[8].k in the network byte order.
175
+ // #6
176
+ BPF_STMT (BPF_LD + BPF_W + BPF_ABS,
177
+ IPOIB_HEADER_LEN + IP_DEST_ADDR_OFFSET),
178
+ // If this is a broadcast address, skip the next check.
179
+ // #7
180
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0xffffffff , 1 , 0 ),
181
+ // If this is not broadcast address, compare it with the unicast
182
+ // address specified for the interface.
183
+ // #8
184
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0x00000000 , 0 , 4 ),
185
+
186
+ // Get the IP header length. This is achieved by the following
187
+ // (special) instruction that, given the offset of the start
188
+ // of the IP header (offset 24) loads the IP header length.
189
+ // #9
190
+ BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, IPOIB_HEADER_LEN),
191
+
192
+ // Make sure it's to the right port. The following instruction
193
+ // adds the previously extracted IP header length to the given
194
+ // offset to locate the correct byte. The given offset of 26
195
+ // comprises the length of the IPoIB header (24) plus the offset
196
+ // of the UDP destination port (2) within the UDP header.
197
+ // #10
198
+ BPF_STMT (BPF_LD + BPF_H + BPF_IND, IPOIB_HEADER_LEN + UDP_DEST_PORT),
199
+ // The following instruction tests against the default DHCP server port,
200
+ // but the action port is actually set in PktFilterBPF::openSocket().
201
+ // N.B. The code in that method assumes that this instruction is at
202
+ // offset 11 in the program. If this is changed, openSocket() must be
203
+ // updated.
204
+ // #11
205
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, DHCP4_SERVER_PORT, 0 , 1 ),
206
+
207
+ // If we passed all the tests, ask for the whole packet.
208
+ // #12
209
+ BPF_STMT (BPF_RET + BPF_K, (u_int )-1 ),
210
+
211
+ // Otherwise, drop it.
212
+ // #13
213
+ BPF_STMT (BPF_RET + BPF_K, 0 ),
214
+ };
215
+
124
216
}
125
217
126
218
using namespace isc ::util;
@@ -169,16 +261,30 @@ PktFilterLPF::openSocket(Iface& iface,
169
261
struct sock_fprog filter_program;
170
262
memset (&filter_program, 0 , sizeof (filter_program));
171
263
172
- filter_program.filter = dhcp_sock_filter;
173
- filter_program.len = sizeof (dhcp_sock_filter) / sizeof (struct sock_filter );
264
+ if (iface.getHWType () == HTYPE_INFINIBAND) {
265
+ filter_program.filter = dhcp_sock_filter_ib;
266
+ filter_program.len = sizeof (dhcp_sock_filter_ib) / sizeof (struct sock_filter );
267
+
268
+ // Configure the filter program to receive unicast packets sent to the
269
+ // specified address. The program will also allow packets sent to the
270
+ // 255.255.255.255 broadcast address.
271
+ dhcp_sock_filter_ib[8 ].k = addr.toUint32 ();
174
272
175
- // Configure the filter program to receive unicast packets sent to the
176
- // specified address. The program will also allow packets sent to the
177
- // 255.255.255.255 broadcast address.
178
- dhcp_sock_filter[8 ].k = addr.toUint32 ();
273
+ // Override the default port value.
274
+ dhcp_sock_filter_ib[11 ].k = port;
275
+ } else {
276
+ filter_program.filter = dhcp_sock_filter;
277
+ filter_program.len = sizeof (dhcp_sock_filter) / sizeof (struct sock_filter );
278
+
279
+ // Configure the filter program to receive unicast packets sent to the
280
+ // specified address. The program will also allow packets sent to the
281
+ // 255.255.255.255 broadcast address.
282
+ dhcp_sock_filter[8 ].k = addr.toUint32 ();
283
+
284
+ // Override the default port value.
285
+ dhcp_sock_filter[11 ].k = port;
286
+ }
179
287
180
- // Override the default port value.
181
- dhcp_sock_filter[11 ].k = port;
182
288
// Apply the filter.
183
289
if (setsockopt (sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter_program,
184
290
sizeof (filter_program)) < 0 ) {
@@ -315,7 +421,21 @@ PktFilterLPF::receive(Iface& iface, const SocketInfo& socket_info) {
315
421
Pkt4Ptr dummy_pkt = Pkt4Ptr (new Pkt4 (DHCPDISCOVER, 0 ));
316
422
317
423
// Decode ethernet, ip and udp headers.
318
- decodeEthernetHeader (buf, dummy_pkt);
424
+ if (iface.getHWType () == HTYPE_INFINIBAND) {
425
+ decodeIPoIBHeader (buf, dummy_pkt);
426
+
427
+ // The IPoIB header does not contain the local address.
428
+ // Set it from the interface instead.
429
+ if (iface.getMacLen () != HWAddr::INFINIBAND_HWADDR_LEN) {
430
+ isc_throw (SocketReadError,
431
+ " Invalid local hardware address size for IPoIB interface." );
432
+ }
433
+ HWAddrPtr hwaddr (new HWAddr (iface.getMac (), iface.getMacLen (),
434
+ iface.getHWType ()));
435
+ dummy_pkt->setLocalHWAddr (hwaddr);
436
+ } else {
437
+ decodeEthernetHeader (buf, dummy_pkt);
438
+ }
319
439
decodeIpUdpHeader (buf, dummy_pkt);
320
440
321
441
// Read the DHCP data.
@@ -374,11 +494,14 @@ PktFilterLPF::send(const Iface& iface, uint16_t sockfd, const Pkt4Ptr& pkt) {
374
494
pkt->setLocalHWAddr (hwaddr);
375
495
}
376
496
377
-
378
- // Ethernet frame header.
379
- // Note that we don't validate whether HW addresses in 'pkt'
380
- // are valid because they are checked by the function called.
381
- writeEthernetHeader (pkt, buf);
497
+ if (iface.getHWType () == HTYPE_INFINIBAND) {
498
+ writeIPoIBHeader (iface, pkt, buf);
499
+ } else {
500
+ // Ethernet frame header.
501
+ // Note that we don't validate whether HW addresses in 'pkt'
502
+ // are valid because they are checked by the function called.
503
+ writeEthernetHeader (pkt, buf);
504
+ }
382
505
383
506
// IP and UDP header
384
507
writeIpUdpHeader (pkt, buf);
0 commit comments